February 29, 2024 3:45 PM

Finding the Torture You're Comfortable With

At some point last week, I found myself pointed to this short YouTube video of Jerry Seinfeld talking with Howard Stern about work habits. Seinfeld told Stern that he was essentially always thinking about making comedy. Whatever situation he found himself in, even with family and friends, he was thinking about how he could mine it for new material. Stern told him that sounded like torture. Jerry said, yes, it was, but...

Your blessing in life is when you find the torture you're comfortable with.

This is something I talk about with students a lot.

Sometimes it's a current student who is worried that CS isn't for them because too often the work seems hard, or boring. Shouldn't it be easy, or at least fun?

Sometimes it's a prospective student, maybe a HS student on a university visit or a college student thinking about changing their major. They worry that they haven't found an area of study that makes them happy all the time. Other people tell them, "If you love what you do, you'll never work a day in your life." Why can't I find that?

I tell them all that I love what I do -- studying, teaching, and writing about computer science -- and even so, some days feel like work.

I don't use torture as analogy the way Seinfeld does, but I certainly know what he means. Instead, I usually think of this phenomenon in terms of drudgery: all the grunt work that comes with setting up tools, and fiddling with test cases, and formatting documentation, and ... the list goes on. Sometimes we can automate one bit of drudgery, but around the corner awaits another.

And yet we persist. We have found the drudgery we are comfortable with, the grunt work we are willing to do so that we can be part of the thing it serves: creating something new, or understanding one little corner of the world better.

I experienced the disconnect between the torture I was comfortable with and the torture that drove me away during my first year in college. As I've mentioned here a few times, most recently in my post on Niklaus Wirth, from an early age I had wanted to become an architect (the kind who design houses and other buildings, not software). I spent years reading about architecture and learning about the profession. I even took two drafting courses in high school, including one in which we designed a house and did a full set of plans, with cross-sections of walls and eaves.

Then I got to college and found two things. One, I still liked architecture in the same way as I always had. Two, I most assuredly did not enjoy the kind of grunt work that architecture students had to do, nor did I relish the torture that came with not seeing a path to a solution for a thorny design problem.

That was so different from the feeling I had writing BASIC programs. I would gladly bang my head on the wall for hours to get the tiniest detail just the way I wanted it, either in the code or in the output. When the torture ended, the resulting program made all the pain worth it. Then I'd tackle a new problem, and it started again.

Many of the students I talk with don't yet know this feeling. Even so, it comforts some of them to know that they don't have to find The One Perfect Major that makes all their boredom go away.

However, a few others understand immediately. They are often the ones who learned to play a musical instrument or who ran cross country. The pianists remember all the boring finger exercises they had to do; the runners remember all the wind sprints and all the long, boring miles they ran to build their base. These students stuck with the boredom and worked through the pain because they wanted to get to the other side, where satisfaction and joy are.

Like Seinfeld, I am lucky that I found the torture I am comfortable with. It has made this life a good one. I hope everyone finds theirs.


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

January 27, 2024 7:10 PM

Today in "It's not the objects; it's the messages"

Alan Kay is fond of saying that object-oriented programming is not about the objects; it's about the messages. He also looks to the biological world for models of how to think about and write computer programs.

This morning I read two things on the exercise bike that brought these ideas to mind, one from the animal kingdom and one from the human sphere.

First was a surprising little article on how an invasive ant species is making it harder for Kenyan lions to hunt zebras, with elephants playing a pivotal role in the story, too. One of the scientists behind the study said:

"We often talk about conservation in the context of species. But it's the interactions which are the glue that holds the entire system together."

It's not just the animals. It's the interactions.

Then came @jessitron reflecting on what it means to be "the best":

And then I remembered: people are people through other people. Meaning comes from between us, not within us.

It's not just the people. It's the interactions.

Both articles highlighted that we are usually better served by thinking about interactions within systems, and not simply the components of system. That way lies a more reliable approach to build robust software. Alan Kay is probably somewhere nodding his head.

The ideas in Jessitron's piece fit nicely into the software analogy, but they mean even more in the world of people that she is reflecting on. It's easy for each of us to fall into the habit of walking around the world as an I and never quite feeling whole. Wholeness comes from connection to others. I occasionally have to remind myself to step back and see my day in terms of the students and faculty I've interacted with, whom I have helped and who have helped me.

It's not (just) the people. It's the interactions.


Posted by Eugene Wallingford | Permalink | Categories: General, Software Development

November 24, 2023 12:17 PM

And Then Came JavaScript

It's been a long time again between posts. That seems to be the new normal. On top of that, though, teaching web development this fall for the first time has been soaking up all of my free hours in the evenings and over the weekends, which has left me little time to be sad about not blogging. I've certainly been writing plenty of text and a bit of code.

The course started off with a lot of positive energy. The students were excited to learn HTML and CSS. I made a few mistakes in how I organized and presented topics, but things went pretty well. By all accounts, students seemed to enjoy what they were learning and doing.

And then came JavaScript.

Well, along came real computer programming. It could have been Python or some other language, I think, but the transition to writing programs, even short bits of code, took the wind out of the students' excitement.

I was prepared for the possibility that the mood of the course would change when we shifted from CSS to JavaScript. A previous offering of the course had encountered a similar obstacle. Learning to program is a challenge. I'm still not convinced that learning to program is that much harder than a lot of things people learn to do, but it does take time.

As I prepared for the course last summer, I saw so many different approaches to teaching JavaScript for web development. Many assumed a lot of HTML/CSS/DOM background, certainly more than my students had picked up in six weeks. Others assumed programming experience most of my students didn't have, even when the approach said 'no experience necessary!'. So I had to find a middle path.

a colorful cube with sides labeled HTML, CSS, and JS
Source: MDN, CC BY-SA 2.5

My main source of inspiration in the first half of the course was David Humphrey's WEB 222 course, which was explicitly aimed at an audience of CS students with programming experience. So I knew that I had to do something different with my students, even as I used his wonderful course materials whenever I could.

My department had offered this course once many years ago, aimed at much the same kind of audience as mine, and the instructor — a good friend — shared all of his materials. I used that offering as a primary source of ideas for getting started with JavaScript, and I occasionally adapted examples for use in my class.

The results were not ideal. Students don't seem to have enjoyed this part of the course much at all. Some acknowledged that to me directly. Even the most engaged students seemed to lose a bit of their energy for the course. Performance also sagged. Based on homework solutions and a short exam, I would say that only one student has achieved the outcomes I had originally outlined for this unit.

I either expected too much or did not do a good enough job helping students get to where I wanted them to be.

I have to do better next time.

But how?

Programming isn't as hard as some people tell us, but most of us can't learn to do it in five or six weeks, at least not enough to become very productive. We don't expect students to master all of CSS or even HTML in such a short time, so we can't expect them to master JavaScript either. The difference is that there seems to be a smooth on-ramp for learning HTML and CSS on the way to mastery, while JavaScript (or any other programming language) presents a steep climb, with occasional plateaus.

For now, I am thinking that the key to doing better is to focus on an even narrower set of concepts and skills.

If people starting from scratch can't learn all of JavaScript in five or six weeks, or even enough to be super-productive, what useful skills can they learn in that time? For this course I trimmed down the set of topics that we might cover in an intro CS considerably, but I think I need to trim even more and — more importantly — choose topics and examples that are even more embedded in the act of web development.

Earlier this week, a sudden burst of thought outlined something like this:

  • document.querySelector() to select an element in a page
  • simple assignment statements to modify innerText, innerHTML, and various style attributes
  • parameterizing changes to an element to create a function
  • document.querySelectorAll() to select collections of elements in a page
  • forEach to process every element in a collection
  • guarded actions to select items in the collection using if statements, without else clauses

That is a lot to learn in five weeks! Even so, it cuts way back on several topics I tried cover this time, such as a more general discussion of objects, arrays, and boolean values, and a deeper look at the DOM. And it eliminates even mentioning several topics altogether:

  • if-else statements
  • while statements
  • counted for loops and, more generally, map-like behavior
  • any fiddling with numbers and arithmetic, which are often used to learn assignment statements, if statements, and function

There are so many things a programmer can't do without these concepts, such as writing an indefinite data validation loop or really understanding what's going on in the DOM tree. But trying to cover all of those topics too did not result in students being able to do them either! I think it left them confused, with so many new ideas jumbled in their minds, and a general dissatisfaction at being unable to use JavaScript effectively.

Of course I would want to build hooks into the course for students who want to go deeper and are ready to do so. There is so much good material on the web for people who are ready for more. Providing more enriched opportunities for advanced students is easier than designing learning opportunities for beginners.

Can something like this work?

I won't know for a while. It will be at least a year before I teach this course again. I wish I could teach it again sooner, so that I could try some of my new ideas and get feedback on them sooner. Such is the curse of a university calendar and once-yearly offerings.

It's too late to make any big changes in trajectory this semester. We have only two weeks after the current one-week Thanksgiving break. Next week, we will focus on input forms (HTML), styling (CSS), and a little data validation (HTML+JavaScript). I hope that this return to HTML+CSS helps us end the course on a positive note. I'd like for students to finish with a good feeling about all they have learned and now can do.


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

October 31, 2023 7:12 PM

The Spirit of Spelunking

Last month, Gus Mueller announced v7.4.3 of his image-editing tool Acorn. This release has a fun little extra built in:

One more super geeky thing I've added is a JavaScript Console:

...

This tool is really meant for folks developing plugins in Acorn, and it is only accessible from the Command Bar, but a part of me absolutely loves pointing out little things like this. I was just chatting with Brent Simmons the other day at Xcoders how you can't really spelunk in apps any more because of all the restrictions that are (justifiably) put on recent MacOS releases. While a console isn't exactly a spelunking tool, I still think it's kind of cool and fun and maybe someone will discover it accidentally and that will inspire them to do stupid and entertaining things like we used to do back in the 10.x days.

I have had JavaScript consoles on my mind a lot in the last few weeks. My students and I have used the developer tools in our browsers as part of my web development course for non-majors. To be honest, I had never used a JavaScript console until this summer, when I began preparing for the course in earnest. REPLs are, of course, a big part of the programming background, from Lisp to Racket to Ruby to Python, so I took to the console with ease and joy. (My past experience with JavaScript was mostly in Node.js, which has its own REPL.) We just started our fourth week studying JavaScript in class, so my students have started getting used to the console. At the outset, it was new to most of them, who have never programmed before. Our attention has now turned to interacting with the DOM and manipulating the content of web page. It's been a lot of fun for me. I'm not sure how it feels for all of my students, though. Many came to the course for web design and really enjoy HTML and CSS. JavaScript, on the other hand, is... programming: more syntax, more semantics, and a lot of new details just to select, say, the third h3 on the page.

Sometimes, you just gotta work over the initial hump to sense the power and fun. Some of them are getting there.

Today I had great fun showing them how to add some simple search functionality to a web page. It was our first big exercise using document.querySelectorAll() and processing a collection of HTML elements. Soon we'll learn about text fields and buttons and events, at which point my The Books of Bokonon will become much more useful to the many readers who still find pleasure in it. Just last night that page got its first modern web styling in the form of a CSS style sheet. For its first twenty-four years of existence, it was all 1990s-era HTML and pseudo-layout using <center>, <hr>, and <br> tags.

Anyway, I appreciate Gus's excitement at adding a console to Acorn, making his tool a place to play as well as work. Spread the joy.


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

September 22, 2023 8:38 PM

Time and Words

Earlier this week, I posted an item on Mastodon:

After a few months studying and using CSS, every once in a while I am able to change a style sheet and cause something I want to happen. It feels wonderful. Pretty soon, though, I'll make a typo somewhere, or misunderstand a property, and not be able to make anything useful happen. That makes me feel like I'm drowning in complexity.

Thankfully, the occasional wonderful feelings — and my strange willingness to struggle with programming errors — pull me forward.

I've been learning a lot while preparing to teach to our web development course [ 1 | 2 ]. Occasionally, I feel incompetent, or not very bright. It's good for me.

I haven't been blogging lately, but I've been writing lots of words. I've also been re-purposing and adapting many other words that are licensed to be reusable (thanks, David Humphrey and John Davis). Prepping a new course is usually prime blogging time for me, with my mind in a constant state of churn, but this course has me drowning in work to do. There is so much to learn, and so much new material — readings, session plans and notes, examples, homework assignments — to create.

I have made a few notes along the way, hoping to expand them into posts. Today they become part of this post.

VS Code

This is my first time in a long time using an editor configured to auto-complete and do all the modern things that developers expect these days. I figured, new tool, why not try a new workflow...

After a short period of breaking in, I'm quite enjoying the experience. One feature I didn't expect to use so much is the ability to collapse an HTML element. In a large HTML file, this has been a game changer for me. Yes, I know, this is old news to most of you. But as my brother loves to say when he gets something used or watches a movie everyone else has already seen, "But, hey, it's new to me!" VS Code's auto-complete across HTML, CSS, and JavaScript, with built-in documentation and links to MDN's more complete documentation, lets me type code much faster than ever before. It made me think of one of my favorite Kent Beck lines:

As the speed of development approaches infinity, reuse becomes irrelevant.

When programming, I often copy, paste, and adapt previous code. In VS Code, I have found myself moving fast enough that copy, paste, and adapt would slow me down. That sort of reuse has become irrelevant.

Examples > Prose

The class sessions for which I have written the longest and most complete notes for my students (and me) tend to be the ones for which I have the fewest, or least well-developed, code examples. The reverse is also true: lots of good examples and code tends to mean smaller class notes. Sometimes that is because I run out of time to write much prose to accompany the session. Just as often, though, it's because the examples give us plenty to do live in class, where the learning happens in the flow of writing and examining code.

This confirms something I've observed over many years of teaching: Examples First tends to work better for most students, even people like me who fancy themselves as top-down thinkers. Good examples and code exercises can create the conditions in which abstract knowledge can be learned. This is a sturdy pedagogical pattern.

Concepts and Patterns

There is so, so much to CSS! HTML itself has a lot of details for new coders to master before they reach fluency. Many of the websites aimed at teaching and presenting these topics quickly begin to feel like a downpour of information, even when the authors try to organize it all. It's too easy to fall into, "And then there's this other property...".

After a few weeks, I've settled into trying to help students learn two kinds of things for each topic:

  • a couple of basic concepts or principles
  • a few helpful patterns
My challenge is that I am still new enough to modern web design that identifying either in advance is a challenge. My understanding is constantly evolving, so my examples and notes are evolving, too. I will be better next time, or so I hope.

~~~~~

We are only five weeks into a fifteen week semester, so take any conclusions I draw with a grain of salt. We also haven't gotten to JavaScript yet, the teaching and learning of which will present a different sort of challenge than HTML and CSS with students who have little or no experience programming. Maybe I will make time to write up our experiences with JavaScript in a few weeks.


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

July 31, 2023 2:35 PM

Learning CSS By Doing It

I ran across this blog post earlier this summer when browsing articles on CSS, as one does while learning CSS for a fall course. Near the end, the writer says:

This is thoroughly exciting to me, and I don't wanna whine about improvements in CSS, but it's a bit concerning since I feel like what the web is now capable of is slipping through my fingers. And I guess that's what I'm worried about; I no longer have a good idea of how these things interact with each other, or where the frontier is now.

The map of CSS in my mind is real messy, confused, and teetering with details that I can't keep straight in my head.

Imagine how someone feels as they learn CSS basically from the beginning and tries to get a handle both on how to use it effectively and how to teach it effectively. There is so much there... The good news, of course, is that our course is for folks with no experience, learning the basics of HTML, CSS, and JavaScript from the beginning, so there is only so far we can hope to go in fifteen weeks anyway.

My impressions of HTML and CSS at this point are quite similar: very little syntax, at least for big chunks of the use cases, and lots and lots of vocabulary. Having convenient access to documentation such as that available at developer.mozilla.org via the web and inside VS Code makes exploring all of the options more manageable in context.

I've been watching Dave Humphrey's videos for his WEB 222 course at Seneca College and learning tons. Special thanks to Dave for showing me a neat technique to use when learning -- and teaching -- web development: take a page you use all the time and try to recreate it using HTML and CSS, without looking at the page's own styles. He has done that a couple times now in his videos, and I was able to integrate the ideas we covered about the two languages in previous videos as Dave made the magic work. I have tried it once on my own. It's good fun and a challenging exercise.

Learning layout by viewing page source used to be easier in the old days, when pages were simpler and didn't include dozens of CSS imports or thousands of scripts. Accepting the extra challenge of not looking at a page's styles in 2023 is usually the simpler path.

Two re-creations I have on tap for myself in the coming days are a simple Wikipedia-like page for myself (I'm not notable enough to have an actual Wikipedia page, of course) and a page that acts like my Mastodon home page, with anchored sidebars and a scrolling feed in between. Wish me luck.


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

July 10, 2023 12:28 PM

What We Know Affects What We See

Last time I posted this passage from Shop Class as Soulcraft, by Matthew Crawford:

Countless times since that day, a more experienced mechanic has pointed out to me something that was right in front of my face, but which I lacked the knowledge to see. It is an uncanny experience; the raw sensual data reaching my eye before and after are the same, but without the pertinent framework of meaning, the features in question are invisible. Once they have been pointed out, it seems impossible that I should not have seen them before.

We perceive in part based on what we know. A lack of knowledge can prevent us from seeing what is right in front of us. Our brains and eyes work together, and without a perceptual frame, they don't make sense of the pattern. Once we learn something, our eyes -- and brains -- can.

This reminds me of a line from the movie The Santa Clause, which my family watched several times when my daughters were younger. The new Santa Claus is at the North Pole, watching magical things outside his window, and comments to the elf whose been helping him, "I see it, but I don't believe it." She replies that adults don't understand: "Seeing isn't believing; believing is seeing." As a mechanic, Crawford came to understand that knowing is seeing.

Later in the book, Crawford describes another way that knowing and perceiving interact with one another, this time with negative results. He had been struggling to figure out why there was no spark at the spark plugs in his VW Bug, and his father -- an academic, not a mechanic -- told him about Ohm's Law:

Ohm's law is something explicit and rulelike, and is true in the way that propositions are true. Its utter simplicity makes it beautiful; a mind in possession of this equation is charmed with a sense of its own competence. We feel we have access to something universal, and this affords a pleasure that is quasi-religious, perhaps. But this charm of competence can get in the way of noticing things; it can displace, or perhaps hamper the development of, a different kind of knowledge that may be difficult to bring to explicit awareness, but is superior as a practical matter. It superiority lies in the fact that it begins with the typical rather than the universal, so it goes more rapidly and directly to particular causes, the kind that actually tend to cause ignition problems.

Rule-based, universal knowledge imposes a frame on the scene. Unfortunately, its universal nature can impede perception by blinding us to the particular details of the situation we are actually in. Instead of seeing what is there, we see the scene as our knowledge would have it.

the cover of the book Drawing on the Right Side of the Brain

This reminds me of a story and a technique from the book Drawing on the Right Side of the Brain, which I first wrote about in the earliest days of this blog. When asked to draw a chair, most people barely even look at the chair in front of them. Instead, they start drawing their idea of a chair, supplemented by a few details of the actual chair they see. That works about as well as diagnosing an engine by diagnosing your mind's eye of an engine, rather than the mess of parts in front of you.

In that blog post, I reported my experience with one of Edwards's techniques for seeing the chair, drawing the negative space:

One of her exercises asked the student to draw a chair. But, rather than trying to draw the chair itself, the student is to draw the space around the chair. You know, that little area hemmed in between the legs of the chair and the floor; the space between the bottom of the chair's back and its seat; and the space that is the rest of the room around the chair. In focusing on these spaces, I had to actually look at the space, because I don't have an image in my brain of an idealized space between the bottom of the chair's back and its seat. I had to look at the angles, and the shading, and that flaw in the seat fabric that makes the space seem a little ragged.

Sometimes, we have to trick our eyes into seeing, because otherwise our brains tell us what we see before we actually look at the scene. Abstract universal knowledge helps us reason about what we see, but it can also impede us from seeing in the first place.

What we know both enables and hampers what we perceive. This idea has me thinking about how my students this fall, non-CS majors who want to learn how to develop web sites, will encounter the course. Most will be novice programmers who don't know what they see when they are looking at code, or perhaps even at a page rendered in the browser. Debugging code will be a big part of their experience this semester. Are there exercises I can give them to help them see accurately?

As I said in my previous post, there's lots of good stuff happening in my brain as I read this book. Perhaps more posts will follow.


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

May 19, 2023 2:57 PM

Help! Teaching Web Development in 2023

With the exception of teaching our database course during the COVID year, I have been teaching a stable pair of courses for the last many semesters: Programming Languages in the spring and our compilers course, Translation of Programming Languages, in the fall. That will change this fall due to some issues with enrollments and course demands. I'll be teaching a course in client-side web development.

The official number and title of the course are "CS 1100 Web Development: Client-Side Coding". The catalog description for the course was written years ago by committee:

Client-side web development adhering to current Web standards. Includes by-hand web page development involving basic HTML, CSS, data acquisition using forms, and JavaScript for data validation and simple web-based tools.

As you might guess from the 1000-level number, this is an introductory course suitable for even first-year students. Learning to use HTML, CSS, and Javascript effectively is the focal point. It was designed as a service course for non-majors, with the primary audience these days being students in our Interactive Digital Studies program. Students in that program learn some HTML and CSS in another course, but that course is not a prerequisite to ours. A few students will come in with a little HTML5+CSS3 experience, but not all.

So that's where I am. As I mentioned, this is one of my first courses to design from scratch in a long time. Other than Database Systems, we have to go back to Software Engineering in 2009. Starting from scratch is fun but can be daunting, especially in a course outside my core competency of hard-core computer science.

The really big change, though, was mentioned two paragraphs ago: non-majors. I don't think I've taught non-majors since teaching my university's capstone 21 years ago -- so long ago that this blog did not yet exist. I haven't taught a non-majors' programming course in even longer, 25 years or more, when I last taught BASIC. That is so long ago that their was no "Visual" in the language name!

So: new area, new content, new target audience. I have a lot of work to do this summer.

I could use some advice from those of you who do web development for a living, who know someone who does, or who are more up to date on the field than I.

Generally, what should a course with this title and catalog description be teaching to beginners in 2023?

Specifically, can you point me toward...

  • similar courses with material online that I could learn from?
  • resources for students to use as they learn: websites, videos, even books?

For example, a former student and now friend mentioned that the w3schools website includes a JavaScript tutorial which allows students to type and test code within the web browser. That might simplify practice greatly for non-CS students while they are learning other development tools.

I have so many questions to answer about tools in particular right now: Should we use an IDE or a simple text editor? Which one? Should we learn raw JavaScript or a simple framework? If a framework, which one?

This isn't a job-training course, but to the extent that's reasonable I would like for students to see a reasonable facsimile of what they might encounter out in industry.

Thinking back, I guess I'm glad now that I decided to play some around with JavaScript in 2022... At least I now have more context for evaluatins the options available for this course.

If you have any thoughts or suggestions, please do send them along. Sending email or replying on Mastodon or Twitter all work. I'll keep you posted on what I learn.


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

April 24, 2023 2:54 PM

PyCon Day 3

The last day of a conference is often a wildcard. If it ends early enough, I can often drive or fly home afterward, which means that I can attend all of the conference activities. If not, I have to decide between departing the next day or cutting out early. When possible, I stay all day. Sometimes, as with StrangeLoop, I can stay all day, skip only the closing keynote, and drive home into the night.

With virtual PyCon, I decided fairly early on that I would not be able to attend most of the last day. This is Sunday, I have family visiting, and work looms on the horizon for Monday. An afternoon talk or two is all I will be able to manage.

Talk 1: A Pythonic Full-Text Search

The idea of this talk was to use common Python tools to implement full-text search of a corpus. It turns out that the talk focused on websites, and thus on tools common to Python web developers: PostgreSQL and Django. It also turns out that django.contrib.postgres provides lots of features for doing search out of the box. This talk showed how to use them.

This was an interesting talk, but not immediately useful to me. I don't work with Django, and I use SQLite more often then PostgreSQL for my personal work. There may be some support for search in django.contrib.sqlite, if it exists, but the speaker said that I'd likely have to implement most of the search functionality myself. Even so, I enjoyed seeing what was possible with modules already available.

Talk 2: Using Python to Help the Unhoused

I thought I was done for the conference, but I decided I could listen in one one more talk while making dinner. This non-technical session sounded interesting:

How a group of volunteers from around the globe use Python to help an NGO in Victoria, BC, Canada to help the unhoused. By building a tool to find social media activity on unhoused in the Capitol Region, the NGO can use a dashboard of results to know where to move their limited resources.

With my attention focused on the Sri Lankan dal with coconut-lime kale in my care, I didn't take detailed notes this time, but I did learn about the existence of Statistics Without Borders, which sounds like a cool public service group that needs to exist in 2023. Otherwise, the project involved scraping Twitter as a source of data about the needs of the homeless in Victoria, and using sentiment analysis to organize the data. Filtering the data to zero in on relevant data was their biggest challenge, as keyword filters passed through many false positives.

At this point, the developers have given their app to the NGO and are looking forward to receiving feedback, so that they can make any improvements that might be needed.

This is a nice project by folks giving back to their community, and a nice way to end the conference.

~~~~~

I was a PyCon first-timer, attending virtually. The conference talks were quite good. Thanks to everyone who organized the conference and created such a complete online experience. I didn't use all of the features available, but what I did use worked well, and the people were great. I ended up with links to several Python projects to try out, a few example scripts for PyScript and Mermaid that I cobbled together after the talks, and lots of syntactic abstractions to explore. Three days well spent.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

April 23, 2023 12:09 PM

PyCon Day 2

Another way that attending a virtual conference is like the in-person experience: you can oversleep, or lose track of time. After a long morning of activity before the time-shifted start of Day 2, I took a nap before the 11:45 talk, and...

Talk 1: Python's Syntactic Sugar

Grrr. I missed the first two-thirds of this talk, which I greatly anticipated, but I slept longer than I planned. My body must have needed more than I was giving it.

I saw enough of the talk, though, to know I want to watch the video on YouTube when it shows up. This topic is one of my favorite topics in programming languages: What is the smallest set of features we need to implement the rest of the language? The speaker spent a couple of years implementing various Python features in terms of others, and arrived at a list of only ten that he could not translate away. The rest are sugar. I missed the list at the beginning of the talk, but I gathered a few of its members in the ten minutes I watched: while, raise, and try/except.

I love this kind of exercise: "How can you translate the statement if X: Y into one that uses only core features?" Here's one attempt the speaker gave:

    try:
        while X:
	    Y
	    raise _DONE
    except _DONE:
        None
 

I was today days old when I learned that Python's bool subclasses int, that True == 1, and that False == 0. That bit of knowledge was worth interrupting my nap to catch the end of the talk. Even better, this talk was based on a series of blog posts. Video is okay, but I love to read and play with ideas in written form. This series vaults to the top of my reading list for the coming days.

Talk 2: Subclassing, Composition, Python, and You

Okay, so this guy doesn't like subclasses much. Fair enough, but... some of his concerns seem to be more about the way Python classes work (open borders with their super- and subclasses) than with the idea itself. He showed a lot of ways one can go wrong with arcane uses of Python subclassing, things I've never thought to do with a subclass in my many years doing OO programming. There are plenty of simpler uses of inheritance that are useful and understandable.

Still, I liked this talk, and the speaker. He was honest about his biases, and he clearly cares about programs and programmers. His excitement gave the talk energy. The second half of the talk included a few good design examples, using subclassing and composition together to achieve various ends. It also recommended the book Architecture Patterns with Python. I haven't read a new software patterns book in a while, so I'll give this one a look.

Toward the end, the speaker referenced the line "Software engineering is programming integrated over time." Apparently, this is a Google thing, but it was new to me. Clever. I'll think on it.

Talk 3: How We Are Making CPython Faster -- Past, Present and Future

I did not realize that, until Python 3.11, efforts to make the interpreter had been rather limited. The speaker mentioned one improvement made in 3.7 to optimize the typical method invocation, obj.meth(arg), and one in 3.8 that sped up global variable access by using a cache. There are others, but nothing systematic.

At this point, the talk became mutually recursive with the Friday talk "Inside CPython 3.11's New Specializing, Adaptive Interpreter". The speaker asked us to go watch that talk and return. If I were more ambitious, I'd add a link to that talk now, but I'll let you any of you are interested to visit yesterday's post and scroll down two paragraphs.

He then continued with improvements currently in the works, including:

  • efforts to optimize over larger regions, such as the different elements of a function call
  • use of partial evaluation when possible
  • specialization of code
  • efforts to speed up memory management and garbage collection

He also mentions possible improvements related to C extension code, but I didn't catch the substance of this one. The speaker offered the audience a pithy takeaway from his talk: Python is always getting faster. Do the planet a favor and upgrade to the latest version as soon as you can. That's a nice hook.

There was lots of good stuff here. Whenever I hear compiler talks like this, I almost immediately start thinking about how I might work some of the ideas into my compiler course. To do more with optimization, we would have to move faster through construction of a baseline compiler, skipping some or all of the classic material. That's a trade-off I've been reluctant to make, given the course's role in our curriculum as a compilers-for-everyone experience. I remain tempted, though, and open to a different treatment.

Talk 4: The Lost Art of Diagrams: Making Complex Ideas Easy to See with Python

Early on, this talk contained a line that programmers sometimes need to remember: Good documentation shows respect for users. Good diagrams, said the speaker, can improve users' lives. The talk was a nice general introduction to some of the design choices available to us as we create diagrams, including the use of color, shading, and shapes (Venn diagrams, concentric circles, etc.). It then discussed a few tools one can use to generate better diagrams. The one that appealed most to me was Mermaid.js, which uses a Markdown-like syntax that reminded me of GraphViz's Dot language. My students and use GraphViz, so picking up Mermaid might be a comfortable task.

~~~~~

My second day at virtual PyCon confirmed that attending was a good choice. I've seen enough language-specific material to get me thinking new thoughts about my courses, plus a few other topics to broaden the experience. A nice break from the semester's grind.


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

April 22, 2023 6:38 PM

PyCon Day 1

One of great benefits of a virtual conference is accessibility. I can hop from Iowa to Salt Lake City with the press of a button. The competing cost to virtual conference is that I am accessible ... from elsewhere.

On the first day of PyCon, we had a transfer orientation session that required my presence in virtual Iowa from 10:00 AM-12:00 noon local time. That's 9:00-11:00 Mountain time, so I missed Ned Batchelder's keynote and the opening set of talks. The rest of the day, though, I was at the conference. Virtual giveth, and virtual taketh away.

Talk 1: Inside CPython 3.11's New Specializing, Adaptive Interpreter

As I said yesterday, I don't know Python -- tools, community, or implementation -- intimately. That means I have a lot to learn in any talk. In this one, Brandt Bucher discussed the adaptive interpreter that is part of Python 3.11, in particular how the compiler uses specialization to improve its performance based on run-time usage of the code.

Midway through the talk, he referred us to a talk on tomorrow's schedule. "You'll find that the two talks are not only complementary, they're also mutually recursive." I love the idea of mutually recursive talks! Maybe I should try this with two sessions in one of my courses. To make it fly, I will need to make some videos... I wonder how students would respond?

This online Python disassembler by @pamelafox@fosstodon.org popped up in the chat room. It looks like a neat tool I can use in my compiler course. (Full disclosure: I have been following Pamela on Twitter and Mastodon for a long time. Her posts are always interesting!)

Talk 2: Build Yourself a PyScript

PyScript is a Javascript module that enables you to embed Python in a web page, via WebAssembly. This talk described how PyScript works and showed some of the technical issues in writing web apps.

Some of this talk was over my head. I also do not have deep experience programming in the web. It looks like I will end up teaching a beginning web development course this fall (more later), so I'll definitely be learning more about HTML, CSS, and Javascript soon. That will prepare me to be more productive using tools like PyScript.

Talk 3: Kill All Mutants! (Intro to Mutation Testing)

Our test suites are often not strong enough to recognize changes in our code. The talk introduced mutation testing, which modifies code to test the suite. I didn't take a lot of notes on this one, but I did make a note to try mutation testing out, maybe in Racket.

Talk 4: Working with Time Zones: Everything You Wish You Didn't Need to Know

Dealing with time zones is one of those things that every software engineer seems to complain about. It's a thorny problem with both technical and social dimensions, which makes it really interesting for someone who loves software design to think about.

This talk opened with example after example of how time zones don't behave as straightforwardly as you might think, and then discussed Python's newest time zone library, pytz.

My main takeaways from this talk: pytz looks useful, and I'm glad I don't have to deal with time zones on a regular basis.

Talk 5: Pythonic Functional (iter)tools for your Data Challenges

This is, of course, a topic after my heart. Functional programming is a big part of my programming languages course, and I like being able to show students Python analogues to the Racket ideas they are learning. There was not much new FP content for me here, but I did learn some new Python functions from itertools that I can use in class -- and in my own code. I enjoyed the Advent of Code segment of the talk, in which the speaker applied Python to some of the 2021 challenges. I use an Advent of Code challenge or two each year in class, too. The early days of the month usually feature fun little problems that my students can understand quickly. They know how to solve them imperatively in Python, but we tackle them functionally in Racket.

Most of the FP ideas needed to solve them in Python are similar, so it was fun to see the speaker solve them using itertools. Toward the end, the solutions got heavy quickly, which must be how some of my students feel when we are solving these problems in class.

~~~~~

Between work in the morning and the conference afternoon and evening, this was a long day. I have a lot of new tools to explore.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

April 21, 2023 3:33 PM

Headed to PyCon, Virtually

Last night, I posted on Mastodon:

Heading off to #PyConUS in the morning, virtually. I just took my first tour of Hubilo, the online platform. There's an awful lot going on, but you need a lot of moving parts to produce the varied experiences available in person. I'm glad that people have taken up the challenge.

Why PyCon? I'm not an expert in the language, or as into the language as I once was with Ruby. Long-time readers may recall that I blogged about attending JRubyConf back in 2012. Here is a link to my first post from that conference. You can scroll up from there to see several more posts from the conference.

However, I do write and read a lot of Python code, because our students learn it early and use it quite a bit. Besides, it's a fun language and has a large, welcoming community. Like many language-specific conferences, PyCon includes a decent number of talks about interpreters, compilers, and tools, which are a big part of my teaching portfolio these days. The conference offers a solid virtual experience, too, which makes it attractive to attend while the semester is still going on.

My goals for attending PyCon this year include:

  • learning some things that will help me improve my programming languages and compiler courses,
  • learning some things that make me a better Python programmer, and
  • simply enjoying computer science and programming for a few days, after a long and occasionally tedious year. The work doesn't go away while I am at a conference, but my mind gets to focus on something else -- something I enjoy!

More about today's talks tomorrow.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

April 09, 2023 8:24 AM

It Was Just Revision

There are several revised approaches to "what's the deal with the ring?" presented in "The History of The Lord of the Rings", and, as you read through the drafts, the material just ... slowly gets better! Bit by bit, the familiar angles emerge. There seems not to have been any magic moment: no electric thought in the bathtub, circa 1931, that sent Tolkien rushing to find a pen.

It was just revision.

Then:

... if Tolkien can find his way to the One Ring in the middle of the fifth draft, so can I, and so can you.

-- Robin Sloan, How The Ring Got Good


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

April 06, 2023 2:59 PM

The Two Meanings of Grace, in Software

In a recent blog post, Why Grace Matters (for Software Development), Avdi Grimm tells the story of how he came to name his training site "Graceful.Dev". Check it out. This passage resolves into the answer:

You know, the word "grace" is interesting, because it has two different meanings. On the one hand, it means beauty in lines or in motion. But if you were raised with a religious background anything like mine, you know that grace is also something that saves you.

And in that moment on the dance floor, I realized that these two meanings of grace are really one and the same thing. Because grace is something that makes space for you to screw up, and then turns it into something beautiful.

I don't think I was raised in the same religious tradition as Avdi, but I was raised in a tradition that valued deeply the notion of grace. Grace manifest in sacrament was a powerful notion to me, one of the religious ideas I found most compelling as I was growing up.

That's probably why Avdi's realization strikes close to home for me. I carry the idea of grace present in other parts of my life as part of my cultural DNA. His connection of grace to software feels right. "Grace makes space for you to screw up, and then turns it into something beautiful." -- I imagine that many programmers know this feeling, in an non-religious way, if only vaguely.


Posted by Eugene Wallingford | Permalink | Categories: Personal, Software Development

March 31, 2023 3:57 PM

"I Just Need a Programmer, er, Writer"

This line line from Chuck Wendig's post on AI tools and writing:

Hell, it's the thing every writer has heard from some jabroni who tells you, "I got this great idea, you write it, we'll split the money 50/50, boom."

... brought to mind one of my most-read blog posts ever, "I Just Need a Programmer":

As head of the Department of Computer Science at my university, I often receive e-mail and phone calls from people with The Next Great Idea. The phone calls can be quite entertaining! The caller is an eager entrepreneur, drunk on their idea to revolutionize the web, to replace Google, to top Facebook, or to change the face of business as we know it. ...

They just need a programmer. ...

The opening of that piece sounds a little harsh more than a decade later, but the basic premise holds. And, as Wendig notes, it holds beyond the software world. I even once wrote a short follow-up when accomplished TV writer Ken Levine commented on his blog about the same phenomenon in screenwriting.

Some misconceptions are evergreen.

Adding AI to the mix adds a new twist. I do think human execution in telling stories will still matter, though. I'm not yet convinced that the AI tools have the depth of network to replace human creativity.

However, maybe tools such as ChatGPT can be the programmer people need. A lot of folks are putting these tools to good use creating prototypes, and people who know how to program are using them effectively as accelerators. Execution will still matter, but these programs may be useful contributors on the path to a product.


Posted by Eugene Wallingford | Permalink | Categories: General, Software Development

March 12, 2023 9:00 AM

A Spectator to Phase Change

Robin Sloan speculates that language-learning models like ChatGPT have gone through a phase change in what they can accomplish.

AI at this moment feels like a mash-up of programming and biology. The programming part is obvious; the biology part becomes apparent when you see AI engineers probing their own creations the way scientists might probe a mouse in a lab.

Like so many people, I find my social media and blog feeds filled with ChatGPT and LLMs and DALL-E and ... speculation about what these tools mean for (1) the production of text and code, and (2) learning to write and program. A lot of that speculation is tinged with fear.

I admire Sloan's effort to be constructive in his approach to the uncertainty:

I've found it helpful, these past few years, to frame my anxieties and dissatisfactions as questions. For example, fed up with the state of social media, I asked: what do I want from the internet, anyway?

It turns out I had an answer to that question.

Where the GPT-alikes are concerned, a question that's emerging for me is:

What could I do with a universal function — a tool for turning just about any X into just about any Y with plain language instructions?

I admit that I am reacting to these developments slowly compared to many people. That's my style in most things: I am more likely to under-react to a change than to over-react, especially at the onset of the change. In this case, there is no chance of immediate peril, so waiting to see what happens as people use these tools seems like a reasonable reasonable. I haven't made any effort to use these tools actively (or even been moved to), so any speculating I do would be uninformed by personal experience.

Instead, I read as people whose work I respect experiment with these tools and try to make sense of them. Occasionally, I draw a small, tentative conclusion, such as that prompting these generators is a lot like prompting students. After a few months of reading and a little reflection, I still think the biggest risk we face is probably that we tend to change the world around us to accommodate our technologies. If we put these tools to work for us in ways that enhance what we do, then the accommodation will pay off. If not, then we may, as Daniel Steinberg wrote in one of his newsletters, stop asking the questions we want to ask and start asking only the questions these tools can answer.

Professionally, I think most about the effect that ChatGPT and its ilk will have on programming and CS education. In these regards, I've been paying special attention to reports from David Humphrey, such as this blog post on his university's attempt to grapple the widespread availability of these tools. David has approached OpenAI with an open mind and written thoughtfully about the promise and the risk. For example, he has written a lot of code with an LLM assistant and found it improving his ability both to write code and to think about problems. Advanced CS students can benefit from this kind of assistance, too, but David wonders how such tools might interfere with students first learning to program.

What do we educators want from generative programming tools anyway? What do I as a programmer and educator want from them?

So, at this point, my personal interaction with the phase change that Sloan describes has been mostly passive: I read about what others are doing and think about the results of their exploration. Perhaps this post is a guilty conscience asserting that I should be doing more. Really, though, I think of it more as an active form of inaction: an effort to collect some of my thinking as I slowly respond to the changes that are coming. Perhaps some day soon I will feel moved to use of these tools as I write code of my own. For now, though, I am content to watch from the sidelines. You can learn a lot just by watching.


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

March 05, 2023 9:47 AM

Context Matters

In this episode of Conversations With Tyler, Cowen asks economist Jeffrey Sachs if he agrees with several other economists' bearish views on a particular issue. Sachs says they "have been wrong ... for 20 years", laughs, and goes on to say:

They just got it wrong time and again. They had failed to understand, and the same with [another economist]. It's the same story. It doesn't fit our model exactly, so it can't happen. It's got to collapse. That's not right. It's happening. That's the story of our time. It's happening.

"It doesn't fit our model, so it can't happen." But it is happening.

When your model keeps saying that something can't happen, but it keeps happening anyway, you may want to reconsider your model. Otherwise, you may miss the dominant story of the era -- not to mention being continually wrong.

Sachs spends much of his time with Cowen emphasizing the importance of context in determining which model to use and which actions to take. This is essential in economics because the world it studies is simply too complex for the models we have now, even the complex models.

I think Sachs's insight applies to any discipline that works with people, including education and software development.

The topic of education even comes up toward the end of the conversation, when Cowen asks Sachs how to "fix graduate education in economics". Sachs says that one of its problems is that they teach econ as if there were "four underlying, natural forces of the social universe" rather than studying the specific context of particular problems.

He goes on to highlight an approach that is affecting every discipline now touched by data analytics:

We have so much statistical machinery to ask the question, "What can you learn from this dataset?" That's the wrong question because the dataset is always a tiny, tiny fraction of what you can know about the problem that you're studying.

Every interesting problem is bigger than any dataset we build from it. The details of the problem matter. Again: context. Sachs suggests that we shouldn't teach econ like physics, with Maxwell's overarching equations, but like biology, with the seemingly arbitrary details of DNA.

In my mind, I immediately began thinking about my discipline. We shouldn't teach software development (or econ!) like pure math. We should teach it as a mix of principles and context, generalities and specific details.

There's almost always a tension in CS programs between timeless knowledge and the details of specific languages, libraries, and tools. Most of students don't go on to become theoretical computer scientists; they go out to work in the world of messy details, details that keep evolving and morphing into something new.

That makes our job harder than teaching math or some sciences because, like economics:

... we're not studying a stable environment. We're studying a changing environment. Whatever we study in depth will be out of date. We're looking at a moving target.

That dynamic environment creates a challenge for those of us teaching software development or any computing as practiced in the world. CS professors have to constantly be moving, so as not to fall our of date. But they also have to try to identify the enduring principles that their students can count on as they go on to work in the world for several decades.

To be honest, that's part of the fun for many of us CS profs. But it's also why so many CS profs can burn out after 15 or 20 years. A never-ending marathon can wear anyone out.

Anyway, I found Cowens' conversation with Jeffrey Sachs to be surprisingly stimulating, both for thinking about economics and for thinking about software.


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

March 01, 2023 2:26 PM

Have Clojure and Racket Overcome the Lisp Curse?

I finally read Rudolf Winestock's 2011 essay The Lisp Curse, which is summarized in one line:

Lisp is so powerful that problems which are technical issues in other programming languages are social issues in Lisp.

It seems to me that Racket and Clojure have overcome the curse. Racket was built by a small team that grew up in academia. Clojure was designed and created by an individual. Yet they are both 100% solutions, not the sort of one-off 80% personal solutions that tend to plague the Lisp world.

But the creators went further: They also attracted and built communities.

The Racket and Clojure communities consist of programmers who care about the entire ecosystem. The Racket community welcomes and helps newcomers. I don't move in Clojure circles, but I see and hear good things from people who do.

Clojure has made a bigger impact commercially, of course. Offering a high level of performance and running on the JVM have their advantages. I doubt either will ever displace Java or the other commercial behemoths, but they appear to have staying power. They earned that status by solving both technical issues and social issues.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

February 11, 2023 1:53 PM

What does it take to succeed as a CS student?

Today I received an email message similar to this:

I didn't do very well in my first semester, so I'm looking for ways to do better this time around. Do you have any ideas about study resources or tips for succeeding in CS courses?

As an advisor, I'm occasionally asked by students for advice of this sort. As department head, I receive even more queries, because early on I am the faculty member students know best, from campus visits and orientation advising.

When such students have already attempted a CS course or two, my first step is always to learn more about their situation. That way, I can offer suggestions suited to their specific needs.

Sometimes, though, the request comes from a high school student, or a high school student's parent: What is the best way to succeed as a CS student?

To be honest, most of the advice I give is not specific to a computer science major. At a first approximation, what it takes to succeed as a CS student is the same as what it takes to succeed as a student in any major: show up and do the work. But there are a few things a CS student does that are discipline-specific, most of which involve the tools we use.

I've decided to put together a list of suggestions that I can point our students to, and to which I can refer occasionally in order to refresh my mind. My advice usually includes one or all of these suggestions, with a focus on students at the beginning of our program:

  • Go to every class and every lab session. This is #0 because it should go without saying, but sometimes saying it helps. Students don't always have to go to their other courses every day in order to succeed.

  • Work steadily on a course. Do a little work on your course, both programming and reading or study, frequently -- every day, if possible. This gives your brain a chance to see patterns more often and learn more effectively. Cramming may help you pass a test, but it doesn't usually help you learn how to program or make software.

  • Ask your professor questions sooner rather than later. Send email. Visit office hours. This way, you get answers sooner and don't end up spinning your wheels while doing homework. Even worse, feeling confused can lead you to shying away from doing the work, which gets in the way of #1.

  • Get to know your programming environment. When programming in Python, simply feeling comfortable with IDLE, and with the file system where you store your programs and data, can make everything else seem easier. Your mind doesn't have to look up basic actions or worry about details, which enables you to make the most of your programming time: working on the assigned task.

  • Spend some of your study time with IDLE open. Even when you aren't writing a program, the REPL can help you! It lets you try out snippets of code from your reading, to see them work. You can run small experiments of your own, to see whether you understand syntax and operators correctly. You can make up your own examples to fill in the gaps in your understanding of the problem.

    Getting used to trying things out in the interactions window can be a huge asset. This is one of the touchstones of being a successful CS student.

That's what came to mind at the end of a Friday, at the end of a long week, when I sat down to give advice to one student. I'd love to hear your suggestions for improving the suggestions in my list, or other bits of advice that would help our students. Email me your ideas, and I'll make my list better for anyone who cares to read it.


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

January 10, 2023 2:20 PM

Are Major Languages' Parsers Implemented By Hand?

Someone on Mastodon posted a link to a 2021 survey of how the parsers for major languages are implemented. Are they written by hand, or automated by a parser generator? The answer was mixed: a few are generated by yacc-like tools (some of which were custom built), but many are written by hand, often for speed.

My two favorite notes:

Julia's parser is handwritten but not in Julia. It's in Scheme!

Good for the Julia team. Scheme is a fine language in which to write -- and maintain -- a parser.

Not only [is Clang's parser] handwritten but the same file handles parsing C, Objective-C and C++.

I haven't clicked through to the source code for Clang yet but, wow, that must be some file.

Finally, this closing comment in the paper hit close to the heart:

Although parser generators are still used in major language implementations, maybe it's time for universities to start teaching handwritten parsing?

I have persisted in having my compiler students write table-driven parsers by hand for over fifteen years. As I noted in this post at the beginning of the 2021 semester, my course is compilers for everyone in our major, or potentially so. Most of our students will not write another compiler in their careers, and traditional skills like implementing recursive descent and building a table-driven program are valuable to them more generally than knowing yacc or bison. Any of my compiler students who do eventually want to use a parser generator are well prepared to learn how, and they'll understand what's going on when they do, to boot.

My course is so old school that it's back to the forefront. I just had to be patient.

(I posted the seeds of this entry on Mastodon. Feel free to comment there!)


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

January 09, 2023 12:19 PM

Thoughts on Software and Teaching from Last Week's Reading

I'm trying to get back into the habit of writing here more regularly. In the early days of my blog, I posted quick snippets every so often. Here's a set to start 2023.

• Falsework

From A Bridge Over a River Never Crossed:

Funnily enough, traditional arch bridges were built by first having a wood framing on which to lay all the stones in a solid arch (YouTube). That wood framing is called falsework, and is necessary until the arch is complete and can stand on its own. Only then is the falsework taken away. Without it, no such bridge would be left standing. That temporary structure, even if no trace is left of it at the end, is nevertheless critical to getting a functional bridge.

Programmers sometimes write a function or an object that helps them build something else that they couldn't easily have built otherwise, then delete the bridge code after they have written the code they really wanted. A big step in the development of a student programmer is when they do this for the first time, and feel in their bones why it was necessary and good.

• Repair as part of the history of an object

From The Art of Imperfection and its link back to a post on making repair visible, I learned about Kintsugi, a practice in Japanese art...

that treats breakage and repair as part of the history of an object, rather than something to disguise.

I have this pattern around my home, at least on occasion. I often repair my backpack, satchel, or clothing and leave evidence of the repair visible. My family thinks it's odd, but figure it's just me.

Do I do this in code? I don't think so. I tend to like clean code, with no distractions for future readers. The closest thing to Kintsugi I can think of now are comments that mention where some bit of code came from, especially if the current code is not intuitive to me at the time. Perhaps my memory is failing me, though. I'll be on the watch for this practice as I program.

• "It is good to watch the master."

I've been reading a rundown of the top 128 tennis players of the last hundred years, including this one about Pancho Gonzalez, one of the great players of the 1940s, '50s, and '60s. He was forty years old when the Open Era of tennis began in 1968, well past his prime. Even so, he could still compete with the best players in the game.

Even his opponents could appreciate the legend in their midst. Denmark's Torben Ulrich lost to him in five sets at the 1969 US Open. "Pancho gives great happiness," he said. "It is good to watch the master."

The old masters give me great happiness, too. With any luck, I can give a little happiness to my students now and then.


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

December 11, 2022 9:09 AM

Living with AI in a World Where We Change the World to Accommodate Our Technologies

My social media feeds are full of ChatGPT screenshots and speculation these days, as they have been with LLMs and DALL-E and other machine learning-based tools for many months. People wonder what these tools will mean for writers, students, teachers, artists, and anyone who produces ordinary text, programs, and art.

These are natural concerns, given their effect on real people right now. But if you consider the history of human technology, they miss a bigger picture. Technologies often eliminate the need for a certain form of human labor, but they just as often create a new form of human labor. And sometimes, they increase the demand for the old kind of labor! If we come to rely on LLMs to generate text for us, where will we get the text with which to train them? Maybe we'll need people to write even more replacement-level prose and code!

As Robin Sloan reminds us in the latest edition of his newsletter, A Year of New Avenues, we redesign the world to fit the technologies we create and adopt.

Likewise, here's a lesson from my work making olive oil. In most places, the olive harvest is mechanized, but that's only possible because olive groves have been replanted to fit the shape of the harvesting machines. A grove planted for machine harvesting looks nothing like a grove planted for human harvesting.

Which means that our attention should be on how programs like GPT-2 might lead us to redesign the world we live and work in better to accommodate these new tools:

For me, the interesting questions sound more like
  • What new or expanded kinds of human labor might AI systems demand?
  • What entirely new activities do they suggest?
  • How will the world now be reshaped to fit their needs?
That last question will, on the timescale of decades, turn out to be the most consequential, by far. Think of cars ... and of how dutifully humans have engineered a world just for them, at our own great expense. What will be the equivalent, for AI, of the gas station, the six-lane highway, the parking lot?

Many professors worry that ChatGPT makes their homework assignments and grading rubrics obsolete, which is a natural concern in the short run. I'm old enough that I may not live to work in a world with the AI equivalent of the gas station, so maybe that world seems too far in the future to be my main concern. But the really interesting questions for us to ask now revolve around how tools such as these will lead us to redesign our worlds to accommodate and even serve them.

Perhaps, with a little thought and a little collaboration, we can avoid engineering a world for them at our own great expense. How might we benefit from the good things that our new AI technologies can provide us while sidestepping some of the highest costs of, say, the auto-centric world we built? Trying to answer that question is a better long-term use of our time and energy that fretting about our "Hello, world!" assignments and advertising copy.


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

December 04, 2022 9:18 AM

If Only Ants Watched Netflix...

In the essay "On Societies as Organisms", Lewis Thomas says that we "violate science" when we try to read human meaning into the structures and behaviors of insects. But it's hard not to:

Ants are so much like human beings as to be an embarrassment. They farm fungi, raise aphids as livestock, launch armies into wars, use chemical sprays to alarm and confuse enemies, capture slaves. The families of weaver ants engage in child labor, holding their larvae like shuttles to spin out the thread that sews the leaves together for their fungus gardens. They exchange information ceaselessly. They do everything but watch television.

I'm not sure if humans should be embarrassed for still imitating some of the less savory behaviors of insects, or if ants should be embarrassed for reflecting some of the less savory behaviors of humans.

Biology has never been my forte, so I've read and learned less about it than many other sciences. Enjoying chemistry a bit at least helped keep me within range of the life sciences. I was fortunate to grow up in the Digital Age.

But with many people thinking the 21st century will the Age of Biology, I feel like I should get more in tune with the times. I picked up Thomas's now classic The Lives of a Cell, in which the quoted essay appears, as a brief foray into biological thinking about the world. I'm only a few pages in, but it is striking a chord. I can imagine so many parallels with computing and software. Perhaps I can be as at home in the 21st century as I was in the 20th.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Patterns, Software Development

November 27, 2022 9:38 AM

I Toot From the Command Line, Therefore I Am

Like so many people, I have been checking out new social media options in the face of Twitter's upheaval. None are ideal, but for now I have focused most of my attention on Mastodon, a federation of servers implemented using the ActivityPub protocol. Mastodon has an open API, which makes it attractive to programmers. I've had an account there for a few years (I like to grab username wallingf whenever a new service comes out) but, like so many people, hadn't really used it. Now feels more like the time.

On Friday, I spent a few minutes writing a small script that posts to my Mastodon account from the command line. I occasionally find that sort of thing useful, so the script has practical value. Really, though, I just wanted to play a bit in code and take a look at Mastodon's API.

Several people in my feed posted, boosted, and retweeted a link to this DEV Community article, which walks readers through the process of posting a status update using curl or Python. Everything worked exactly as advertised, with one small change: the Developers link that used to be in the bottom left corner of one's Mastodon home page is now a Development link on the Preferences page.

I've read a lot in the last few weeks about how the culture of Mastodon is different from the culture of Twitter. I'm trying to take seriously the different culture. One concrete example is the use of content warnings or spoiler alerts to hide content behind a brief phrase or tag. This seems like a really valuable practice, useful in a number of different contexts. At the very least, it feels like the Subject: line on an email message or a Usenet News post. So I looked up how to post content warnings with my command-line script. It was dead simple, all done in a few minutes.

There may be efficiency problems under the hood with how Mastodon requests work, or so I've read. The public interface seems well done, though.

I went with Python for my script, rather than curl. That fits better with most my coding these days. It also makes it easier to grow the script later, if I want. bash is great for a few lines, but I don't like to live inside bash for very long. On any code longer than a few lines, I want to use a programming language. At a couple of dozen lines, my script was already long enough to merit a real language. I went mostly YAGNI this time around. There are no classes, just a sequence of statements to build the http request from some constants (server name, authorization token) and command-line args (the post, the content warning). I did factor the server name and authorization token out of the longer strings and include an option to write the post via stdin. I want the flexibility of writing longer toots now, and I don't like magic constants. If I ever need to change servers or tokens, I never have to look past the few first few lines of the file.

As I briefly imagined morphing the small but growing script into a Toot class, I recalled a project I gave my Intermediate Computing students back in 2009 or so: implement the barebones framework of a Twitter-like application. That felt cutting edge back then, and most of the students really liked putting their new OO design and programming skills to use in a program that seemed to matter. It was good fun, and a great playground for so many of the ideas they had learned that semester.

All in all, this was a great way to spend a few minutes on a free afternoon. The API was simple to use, and the result is a usable new command. I probably should've been grading or doing some admin work, but profs need a break, too. I'm thankful to enjoy little programming projects so much.


Posted by Eugene Wallingford | Permalink | Categories: General, Software Development

October 31, 2022 6:11 PM

The Inventor of Assembly Language

This weekend, I learned that Kathleen Booth, a British mathematician and computer scientist, invented assembly language. An October 29 obituary reported that Booth died on September 29 at the age of 100. By 1950, when she received her PhD in applied mathematics from the University of London, she had already collaborated on building at least two early digital computers. But her contributions weren't limited to hardware:

As well as building the hardware for the first machines, she wrote all the software for the ARC2 and SEC machines, in the process inventing what she called "Contracted Notation" and would later be known as assembly language.

Her 1958 book, Programming for an Automatic Digital Calculator, may have been the first one on programming written by a woman.

I love the phrase "Contracted Notation".

Thanks to several people in my Twitter feed for sharing this link. Here's hoping that Twitter doesn't become uninhabitable, or that a viable alternative arises; otherwise, I'm going to miss out on a whole lotta learning.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

October 23, 2022 9:54 AM

Here I Go Again: Carmichael Numbers in Graphene

I've been meaning to write a post about my fall compilers course since the beginning of the semester but never managed to set aside time to do anything more than jot down a few notes. Now we are at the end of Week 9 and I just must write. Long-time readers know what motivates me most: a fun program to write in my student's source language!

TFW you run across a puzzle and all you want to do now is write a program to solve it. And teach your students about the process.
-- https://twitter.com/wallingf/status/1583841233536884737

Yesterday, it wasn't a puzzle so much as discovering a new kind of number, Carmichael numbers. Of course, I didn't discover them (neither did Carmichael, though); I learned of them from a Quanta article about a recent proof about these numbers that masquerade as primes. One way of defining this set comes from Korselt:

A positive composite integer n is a Carmichael number if and only if it has multiple prime divisors, no prime divisor repeats, and for each prime divisor p, p-1 divides n-1.

This definition is relatively straightforward, and I quickly imagined am imperative solution with a loop and a list. The challenge of writing a program to verify a number is a Carmichael number in my compiler course's source language is that it has neither of these things. It has no data structures or even local variables; only basic integer and boolean arithmetic, if expressions, and function calls.

Challenge accepted. I've written many times over the years about the languages I ask my students to write compilers for and about my adventures programming in them, from Twine last year through Flair a few years ago to a recurring favorite, Klein, which features prominently in popular posts about Farey sequences and excellent numbers.

This year, I created a new language, Graphene, for my students. It is essentially a small functional subset of Google's new language Carbon. But like it's predecessors, it is something of an integer assembly language, fully capable of working with statements about integers and primes. Korselt's description of Carmichael numbers is right in Graphene's sweet spot.

As I wrote in the post about Klein and excellent numbers, my standard procedure in cases like this is to first write a reference program in Python using only features available in Graphene. I must do this if I hope to debug and test my algorithm, because we do not have a working Graphene compiler yet! (I'm writing my compiler in parallel with my students, which is one of the key subjects in my phantom unwritten post.) I was proud this time to write my reference program in a Graphene-like subset of Python from scratch. Usually I write a Pythonic solution, using loops and variables, as a way to think through the problem, and then massage that code down to a program using a limited set of concepts. This time, I started with short procedural outline:

    # walk up the primes to n
    #   - find a prime divisor p:
    #     - test if a repeat         (yes: fail)
    #     - test if p-1 divides n-1  (no : fail)
    # return # prime divisors > 1
and then implemented it in a single recursive function. The first few tests were promising. My algorithm rejected many small numbers not in the set, and it correctly found 561, the smallest Carmichael number. But when I tested all the numbers up to 561, I saw many false positives. A little print-driven debugging found the main bug: I was stopping too soon in my search for prime divisors, at sqrt(n), due to some careless thinking about factors. Once I fixed that, boom, the program correctly handled all n up to 3000. I don't have a proof of correctness, but I'm confident the code is correct. (Famous last words, I know.)

As I tested the code, it occurred to me that my students have a chance to one-up standard Python. Its rather short standard stack depth prevented my program from reaching even n=1000. When I set sys.setrecursionlimit(5000), my program found the first five Carmichael numbers: 561, 1105, 1729, 2465, and 2821. Next come 6601 and 8911; I'll need a lot more stack frames to get there.

All those stack frames are unnecessary, though. My main "looping" function is beautifully tail recursive: two failure cases, the final answer case checking the number of prime divisors, and two tail-recursive calls that move either to the next prime as potential factor or to the next quotient when we find one. If my students implement proper tail calls -- an optimization that is optional in the course but encouraged by their instructor with gusto -- then their compiler will enable us to solve for values up to the maximum integer in the language, 231-1. We'll be limited only by the speed of the target language's VM, and the speed of the target code the compiler generates. I'm pretty excited.

Now I have to resist the urge to regale my students with this entire story, and with more details about how I approach programming in a language like Graphene. I love to talk shop with students about design and programming, but our time is limited... My students are already plenty busy writing the compiler that I need to run my program!

This lark resulted in an hour or so writing code in Python, a few more minutes porting to Graphene, and an enjoyable hour writing this blog post. As the song says, it was a good day.


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

August 15, 2022 12:49 PM

No Comment

a picture of the orchid in my office from April 2021

From the closing pages from The Orchid Thief, which I mentioned in my previous post:

"The thing about computers," Laroche said, "the thing that I like is that I'm immersed in it but it's not a living thing that's going to leave or die or something. I like having the minimum number of living things to worry about in my life."

Actually, I have two comments.

If Laroche had gotten into open source software, he might have found himself with the opposite problem: software that won't die. Programmers sometimes think, "I know, I'll design and implement my own programming language!" Veterans of the programming languages community always seem to advise: think twice. If you put something out there, other people will use it, and now you are stuck maintaining a package forever. The same can be said for open source software more generally. Oh, and did I mention it would be really great if you added this feature?

I like having plants in my home and office. They give me joy every day. They also tend to live a lot longer than some of my code. The hardy orchid featured above bloomed like clockwork twice a year for me for five and a half years. Eventually it needed more space than the pot in my office could give, so it's gone now. But I'm glad to have enjoyed it for all those years.


Posted by Eugene Wallingford | Permalink | Categories: General, Personal, Software Development

July 03, 2022 9:00 AM

The Difference Between Medicine and Being a Doctor Is Like ...

Morgan Housel's recent piece on experts trying too hard includes a sentence that made me think of what I teach:

A doctor once told me the biggest thing they don't teach in medical school is the difference between medicine and being a doctor — medicine is a biological science, while being a doctor is often a social skill of managing expectations, understanding the insurance system, communicating effectively, and so on.

Most of the grads from our CS program go on to be software developers or to work in software-adjacent jobs like database administrator or web developer. Most of the rest work in system administration or networks. Few go on to be academic computer scientists. As Housel's doctor knows about medicine, there is a difference between academic computer science and being a software developer.

The good news is, I think the CS profs at many schools are aware of this, and the schools have developed computer science programs that at least nod at the difference in their coursework. The CS program at my school has a course on software engineering that is more practical than theoretical, and another short course that teaches practical tools such as version control, automated testing, and build tools, and skills such as writing documentation. All of our CS majors complete a large project course in which students work in teams to create a piece of software or a secure system, and the practical task of working as a team to deliver a piece of working software is a focus of the course. On top of those courses, I think most of our profs try to keep their courses real for students they know will want to apply what they learn in Algorithms, say, or Artificial Intelligence in their jobs as developers.

Even so, there is always a tension in classes between building foundational knowledge and building practical skills. I encounter this tension in both Programming Languages and Translation of Programming Languages. There are a lot of cool things we could learn about type theory, some of which might turn out to be quite useful in a forty-year career as a developer. But any time we devote to going deeper on type theory is time we can't devote to the concrete languages skills of a software developer, such as learning and creating APIs or the usability of programming languages.

So, we CS profs have to make design trade-offs in our courses as we try to balance the forces of students learning computer science and students becoming software developers. Fortunately, we learn a little bit about recognizing, assessing, and making trade-offs in our work both as computer scientists and as programmers. That doesn't make it easy, but at least we have some experience for thinking about the challenge.

The sentence quoted above reminds me that other disciplines face a similar challenge. Knowing computer science is different from being a software developer, or sysadmin. Knowing medicine is different from being a doctor. And, as Housel explains so well in his own work, knowing finance is different from being an investor, which is usually more about psychology and self-awareness than it is about net present value or alpha ratios. (The current stock market is a rather harsh reminder of that.)

Thanks to Housel for the prompt. The main theme of his piece — that experts makes mistakes that novices can't make, which leads to occasional unexpected outcomes — is the topic for another post.


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

June 07, 2022 12:25 PM

I Miss Repeats

This past weekend, it was supposed to rain Saturday evening into Sunday, so I woke up with uncertainty about my usual Sunday morning bike ride. My exercise bike broke down a few weeks back, so riding outdoors was my only option. I decided before I went to bed on Saturday night that, if it was dry when I woke up, I would ride a couple of miles to a small lake in town and ride laps in whatever time I could squeeze in between rain showers.

The rain in the forecast turned out to be a false alarm, so I had more time to ride than I had planned. I ended up riding the 2.3 miles to the fifteen 1.2-mile laps, and 2.30 miles back home. Fifteen mile-plus laps may seem crazy to you, but it was the quickest and most predictable adjustment I could make in the face of the suddenly available time. It was like a speed workout on the track from my running days. Though shorter than my usual Sunday ride, it was an unexpected gift of exercise on what turned out to be a beautiful morning.

A couple of laps into the ride, the hill on the far end of the loop began to look look foreboding. Thirteen laps to go... Thirteen more times up an extended incline (well, at least what passes for one in east central Iowa).

After a few more laps, my mindset had changed. Six down. This feels good. Let's do nine more!

I had found the rhythm of doing repeats.

I used to do track repeats when training for marathons and always liked them. (One of my earliest blog entries sang the praises of short iterations and frequent feedback on the track.) I felt again the hit of endorphins every time I completed one loop around the lake. My body got into the rhythm. Another one, another one. My mind doesn't switch off under these conditions, but it does shift into a different mode. I'm thinking, but only in the moment of the current lap. Then there's one more to do.

I wonder if this is one of the reasons some programmers like programming with stories of a limited size, or under the constraints of test-driven design. Both provide opportunities for frequent feedback and frequent learning. They also provide a hit of endorphins every time you make a new test pass, or see the light go green after a small refactoring.

My willingness to do laps, at least in service of a higher goal, may border on the unfathomable. One Sunday many years ago, when I was still running, we had huge thunderstorms all morning and all afternoon. I was in the middle of marathon training and needed a 20-miler that day to stay on my program. So I went to the university gym -- the one mentioned in the blog post linked above, with 9.2 laps to a mile -- and ran 184 laps. "Are you nuts?" I loved it! The short iterations and frequent feedback dropped me in to a fugue-like rhythm. It was easy to track my pace, never running too fast or too slow. It was easy to make adjustments when I noticed something off-plan. In between moments checking my time, I watched people, I breathed, I cleared my mind. I ran. All things considered, it was a good day.

Sunday morning's fifteen laps were workaday in comparison. At the end, I wished I had more time to ride. I felt strong enough. Another five laps would have been fun. That hill wasn't going to get me. And I liked the rhythm.


Posted by Eugene Wallingford | Permalink | Categories: Personal, Running, Software Development

May 30, 2022 8:32 AM

I Have Written That Code

Last month, I picked up a copy of The Writing Life by Annie Dillard at the library. It's one of those books that everyone seems to quote, and I had never read it. I was pleased to find it is a slim volume.

It didn't take long to see one of the often-quoted passages, on the page before the first chapter:

No one expects the days to be gods. -- Emerson

Then, about a third of the way in, came the sentences for which everyone knows Dillard:

How we spend our days is, of course, how we spend our lives. What we do with this hour, and that one, is what we are doing.

Dillard's portrayal of the writing life describes some of the mystery that we non-writers imagine, but mostly it depicts the ordinariness of daily grind and the extended focus that looks like obsession to those of us on the outside.

Occasionally, her stories touched on my experience as a writer of programs. Consider this paragraph:

Every year the aspiring photographer brought a stack of his best prints to an old, honored photographer, seeking his judgment. Every year the old man studied the prints and painstakingly ordered them into two piles, bad and good. Every year that man moved a certain landscape print into the bad stack. At length he turned to the young man: "You submit this same landscape every year, and every year I put it on the bad stack. Why do you like it so much?" The young photographer said, "Because I had to climb a mountain to get it."

I have written that code. I bang my head against some problem for days or weeks. Eventually, I find a solution. Sometimes it's homely code that gets the job; usually it seems more elegant than it is, in relief against the work that went into discovering it. Over time, I realize that I need to change it, or delete it altogether, in order to make progress on the system in which it resides. But... the mountain.

It's a freeing moment when I get over the fixation and make the change the code needs. I'll always have the mountain, but my program needs to move in a different direction.


Posted by Eugene Wallingford | Permalink | Categories: General, Software Development

May 24, 2022 4:09 PM

Observing Students Learn to REPL in Dr. Racket

I recently ran across an old post by @joepolitz, Beginner REPL Stumbles, that records some of the ways he has observed students struggle as they learn to use IDEs with REPLs and files. As I mentioned on Twitter, it struck a chord with me even though I don't teach beginning programmers much these days. My tweets led to a short conversation that I'd like to record, and slightly expoand on, here.

I've noticed the first of the struggles in my junior-level Programming Languages class: students not knowing, or not taking seriously enough, the value of ctrl-up to replay and edit a previous interaction. If students cannot work effectively in the REPL, they will resort to typing all of their code in the definitions pane and repeatedly re-running it. This programming style misses out on the immense value of the REPL as a place to evolve code rapidly, with continual feedback, on the way to becoming a program.

As recommended in the post, I now demonstrate ctrl-up early in the course and note whenever I use it in a demo. If a student finds that their keyboard maps ctrl-up to another behavior, I show them how to define a shortcut in Preferences. This simple affordance can have an inordinate effect on the student's programming experience.

The other observations that Politz describes may be true for my students, too, and I just don't see them. My students are juniors and seniors who already have a year of experience in Python and perhaps a semester using Java. We aren't in the lab together regularly. I usually hear about their struggles with content when they ask questions, and when they do, they don't usually ask about process or tools. Sometimes, they will demo some interaction for me and I'll get to see an unexpected behavior in usage and help them, but that's rare.

(I do recall a student coming into my office once a few years ago and opening up a source file -- in Word. They said they had never gotten comfortable with Dr. Racket and that Word helped them make progress typing and editing code faster. We talked about ways to learn and practice Dr. Racket, but I don't think they ever switched.)

Having read about some of the usage patterns that Politz reports, I think I need to find ways to detect misunderstandings and difficulties with tools sooner. The REPL, and the ability to evolve code from interactions in the REPL into programs in the definitions pane, are powerful tools -- if one groks them and learns to use them effectively. As Politz notes, direct instruction is a necessary antidote to address these struggles. Direct instruction up front may also help my students get off to a better start with the tools.

There is so much room for improvement hidden inside assumptions that are baked into our current tools and languages. Observing learners can expose things we never think about, if we pay attention. I wonder what else I have been missing...

Fortunately, both Joe Politz and Shriram Krishnamurthi encountered my tweets. Krishnamurthi provided helpful context, noting that the PLT Scheme team noticed many of these issues in the early days of Dr. Scheme. They noticed others while running teacher training sessions for @Bootstrapworld. In both cases, instructors were in the lab with learners while they used the tools. In the crush to fix more pressing problems, the interaction issues went unaddressed. In my experience, they are also subtle and hard to appreciate fully without repeated exposure.

Politz provided a link to a workshop paper on Repartee, a tool that explicitly integrates interactive programming and whole-program editing. Very cool. As Krishnamurthi noted to close the conversation, Repartee demonstrates that we may be able to do better than simply teach students to use a REPL more effectively. Perhaps we can make better tools.

I've been learning a lot about CS education research the last few years. It is so much more than the sort of surface-level observations and uncontrolled experiments I saw, and made, at the beginning of my career. This kind of research demands a more serious commitment to science but offers the potential of real improvement in return for the effort. I'm glad to know CS ed researchers are making that commitment. I hope to help where I can.


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

March 03, 2022 2:22 PM

Knowing Context Gives You Power, Both To Choose And To Make

We are at the point in my programming languages course where my students have learned a little Racket, a little functional programming, and a little recursive programming over inductive datatypes. Even though I've been able to connect many of the ideas we've studied to programming tasks out in the world that they care about themselves, a couple of students have asked, "Why are we doing this again?"

This is a natural question, and one I'm asked every time I teach this course. My students think that they will be heading out into the world to build software in Java or Python or C, and the ideas we've seen thus far seem pretty far removed from the world they think they will live in.

These paragraphs from near the end of Chelsea Troy's 3-part essay on API design do a nice job of capturing one part of the answer I give my students:

This is just one example to make a broader point: it is worthwhile for us as technologists to cultivate knowledge of the context surrounding our tools so we can make informed decisions about when and how to use them. In this case, we've managed to break down some web request protocols and build their pieces back up into a hybrid version that suits our needs.

When we understand where technology comes from, we can more effectively engage with its strengths, limitations, and use cases. We can also pick and choose the elements from that technology that we would like to carry into the solutions we build today.

The languages we use were designed and developed in a particular context. Knowing that context gives us multiple powers. One power is the ability to make informed decisions about the languages -- and language features -- we choose in any given situation. Another is the ability to make new languages, new features, and new combinations of features that solve the problem we face today in the way that works best in our current context.

Not knowing context limits us to our own experience. Troy does a wonderful job of demonstrating this using the history of web API practice. I hope my course can help students choose tools and write code more effectively when they encounter new languages and programming styles.

Computing changes. My students don't really know what world they will be working in in five years, or ten, or thirty. Context is a meta-tool that will serve them well.


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

February 13, 2022 12:32 PM

A Morning with Billy Collins

It's been a while since I read a non-technical article and made as many notes as I did this morning on this Paris Review interview with Billy Collins. Collins was poet laureate of the U.S. in the early 2000s. I recall reading his collection, Sailing Alone Around the Room, at PLoP in 2002 or 2003. Walking the grounds at Allerton with a poem in your mind changes one's eyes and hears. Had I been blogging by then, I probably would have commented on the experience, and maybe one or two of the poems, in a post.

As I read this interview, I encountered a dozen or so passages that made me think about things I do, things I've thought, and even things I've never thought. Here are a few.

I'd like to get something straightened out at the beginning: I write with a Uni-Ball Onyx Micropoint on nine-by-seven bound notebooks made by a Canadian company called Blueline. After I do a few drafts, I type up the poem on a Macintosh G3 and then send it out the door.

Uni-Ball Micropoint pens are my preferred writing implement as well, though I don't write enough on paper any more to make buying a particular pen much worth the effort. Unfortunately, just yesterday my last Uni-Ball Micro wrote its last line. Will I order more? It's a race between preference and sloth.

I type up most of the things I write these days on a 2015-era MacBook Pro, often connected to a Magic Keyboard. With the advent of the M1 MacBook Pros, I'm tempted to buy a new laptop, but this one serves me so well... I am nothing if not loyal.

The pen is an instrument of discovery rather than just a recording implement. If you write a letter of resignation or something with an agenda, you're simply using a pen to record what you have thought out. In a poem, the pen is more like a flashlight, a Geiger counter, or one of those metal detectors that people walk around beaches with. You're trying to discover something that you don't know exists, maybe something of value.

Programming may be like writing in many ways, but the search for something to say isn't usually one of them. Most of us sit down to write a program to do something, not to discover some unexpected outcome. However, while I may know what my program will do when I get done, I don't always know what that program will look like, or how it will accomplish its task. This state of uncertainty probably accounts for my preference in programming languages over the years. Smalltalk, Ruby, and Racket have always felt more like flashlights or Geiger counters than tape recorders. They help me find the program I need more readily than Java or C or Python.

I love William Matthews's idea--he says that revision is not cleaning up after the party; revision is the party!

Refactoring is not cleaning up after the party; refactoring is the party! Yes.

... nothing precedes a poem but silence, and nothing follows a poem but silence. A poem is an interruption of silence, whereas prose is a continuation of noise.

I don't know why this passage grabbed me. Perhaps it's just the imagery of the phrases "interruption of silence" and "continuation of noise". I won't be surprised if my subconscious connects this to programming somehow, but I ought to be suspicious of the imposition. Our brains love to make connections.

She's this girl in high school who broke my heart, and I'm hoping that she'll read my poems one day and feel bad about what she did.

This is the sort of sentence I'm a sucker for, but it has no real connection to my life. Though high school was a weird and wonderful time for me, as it was for so many, I don't think anything I've ever done since has been motivated in this way. Collins actually goes on to say the same thing about his own work. Readers are people with no vested interest. We have to engage them.

Another example of that is my interest in bridge columns. I don't play bridge. I have no idea how to play bridge, but I always read Alan Truscott's bridge column in the Times. I advise students to do the same unless, of course, they play bridge. You find language like, South won with dummy's ace, cashed the club ace and ruffed a diamond. There's always drama to it: Her thirteen imps failed by a trick. There's obviously lots at stake, but I have no idea what he's talking about. It's pure language. It's a jargon I'm exterior to, and I love reading it because I don't know what the context is, and I'm just enjoying the language and the drama, almost like when you hear two people arguing through a wall, and the wall is thick enough so you can't make out what they're saying, though you can follow the tone.

I feel seen. Back when we took the local daily paper, I always read the bridge column by Charles Goren, which ran on the page with the crossword, crypto cipher, and other puzzles. I've never played bridge; most of what I know about the game comes from reading Matthew Ginsberg's papers about building AI programs to bid and play. Like Collins, I think I was merely enjoying sound of the language, a jargon that sounds serious and silly at the same time.

Yeats summarizes this whole thing in "Adam's Curse" when he writes: "A line will take us hours maybe, / Yet if it does not seem a moment's thought / Our stitching and unstitching has been naught."

I'm not a poet, and my unit of writing is rarely the line, but I know a feeling something like this in writing lecture notes for my students. Most of the worst writing consists of paragraphs and sections I have not spent enough time on. Most of the best sounds natural, a clean distillation of deep understanding. But those paragraphs and sections are the result of years of evolution. That's the time scale on which some of my courses grow, because no course ever gets my full attention in any semester.

When I finish a set of notes, I usually feel like the stitching and unstitching have not yet reached their desired end. Some of the text "seems a moment's thought", but much is still uneven or awkward. Whatever the state of the notes, though, I have move on to the next task: grading a homework assignment, preparing the next class session, or -- worst of all -- performing the administrivia that props up the modern university. More evolution awaits.

~~~~

This was a good read for a Sunday morning on the exercise bike, well recommended. The line on revision alone was worth the time; I expect it will be a stock tool in my arsenal for years to come.


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

January 13, 2022 2:02 PM

A Quick Follow-Up on What Next

My recent post on what language or tool I should dive into next got some engagement on Twitter, with many helpful suggestions. Thank you all! So I figure I should post a quick update to report what I'm thinking at this point.

In that post, I mentioned JavaScript and Pharo by name, though I was open to other ideas. Many folks pointed out the practical value of JavaScript, especially in a context where many of my students know and use it. Others offered lots of good ideas in the Smalltalk vein, both Pharo and several lighter-weight Squeaks. A couple of folks recommended Glamorous Toolkit (GToolkit), from @feenkcom, which I had not heard of before.

I took to mind several of the suggestions that commenters made about the how to think about making the decision. For example, there is more overhead to studying Pharo and GToolkit than JavaScript or one of the lighter-weight Squeaks. Choosing one of the latter would make it easier to tinker. I think some of these comments had students in mind, but they are true even for my own study during the academic semester. Once I get into a term (my course begins one week from today), my attention gets pulled in many directions for fifteen or sixteen weeks. Being able to quickly switch contexts when jumping into a coding session means that I can jump more often and more productively.

Also, as Glenn Vanderburg pointed out, JavaScript and Pharo aren't likely to teach me much new. I have a lot of background with Smalltalk and, in many ways, JavaScript is just another language. The main benefit of working with either would be practical, not educational.

GToolkit might teach me something, though. As I looked into GToolkit, it became more tempting. The code is Smalltalk, because it is implemented in Pharo. But the project has a more ambitious vision of software that is "moldable": easier to understand, easier to figure out. GToolkit builds on Smalltalk's image in the direction of a computational notebook, which is an idea I've long wanted to explore. (I feel a little guilty that I haven't look more into the work that David Schmüdde has done developing a notebook in Clojure.) GToolkit sounds like a great way for me to open several doors at once and learn something new. To do it justice, though, I need more time and focus to get started.

So I have decided on a two-pronged approach. I will explore JavaScript during the spring semester. This will teach me more about a language and ecosystem that are central to many of my students' lives. There is little overhead to picking it up and playing with it, even during the busiest weeks of the term. I can have a little fun and maybe make some connections to my programming languages course along the way. Then for summer, I will turn my attention to GToolkit, and perhaps a bigger research agenda.

I started playing with JavaScript on Tuesday. Having just read a blog post on scripting to compute letter frequencies in Perl, I implemented some of the same ideas in JavaScript. For the most part, I worked just as my students do: relying on vague memories of syntax and semantics and, when that failed, searching about for examples online.

A couple of hours working like this refreshed my memory on the syntax I knew from before and introduced me to some features that were new to me. It took a few minutes to re-internalize the need for those pesky semicolons at the end of every line... The resulting code is not much more verbose than Perl. I drifted pretty naturally to using functional programming style, as you might imagine, and it felt reasonably comfortable. Pretty soon I was thinking more about the tradeoff between clarity and efficiency in my code than about syntax, which is a good sign. I did run into one of JavaScript's gotchas: I used for...in twice instead of for...of and was surprised by the resulting behavior. Like any programmer, I banged my head on wall for a few minutes and then recovered. But I have to admit that I had fun. I like to program.

I'm not sure what I will write next, or when I will move into the browser and play with interface elements. Suggestions are welcome!

I am pretty sure, though, that I'll start writing unit tests soon. I used SUnit briefly and have a lot of experience with JUnit. Is JSUnit a thing?


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

January 04, 2022 2:54 PM

Which Language Next?

I've never been one to write year-end retrospectives on my blog, or prospective posts about my plans for the new year. That won't change this year, this post notwithstanding.

I will say that 2021 was a weird year for me, as it was for many people. One positive was purchasing a 29" ultra-wide monitor for work at home, seen in this post from my Strange Loop series. Programming at home has been more fun since the purchase, as have been lecture prep, data-focused online meetings, and just about everything. The only downside is that it's in my basement office, which hides me away. When I want to work upstairs to be with family, it's back to the 15" laptop screen. First-world problems.

Looking forward, I'm feeling a little itchy. I'll be teaching programming languages again this spring and plan to inject some new ideas, but the real itch is: I am looking for a new project to work on, and a new language to study. This doesn't have to be a new language, just one that one I haven't gone deep on before. I have considered a few, including Swift, but right now I am thinking of Pharo and JavaScript.

Thinking about mastering JavaScript in 2022 feels like going backward. It's old, as programming languages go, and has been a dominant force in the computing world for well over a decade. But it's also the most common language many of my students know that I have never gone deep on. There is great value in studying languages for their novel ideas and academic interest, but there is also value in having expertise with a language and toolchain that my students already care about. Besides, I've really enjoyed reading about work on JIT compilation of JavaScript over the years, and it's been a long time since I wrote code in a prototype-based OO language. Maybe it's time to build something useful in JavaScript.

Studying Pharo would be going backward for me in a different way. Smalltalk always beckons. Long-time followers of this blog have read many posts about my formative experiences with Smalltalk. But it has been twenty years since I lived in an image every day. Pharo is a modern Smalltalk with a big class library and a goal of being suitable for mission-critical systems. I don't need much of a tug; Smalltalk always beckons.

My current quandary brings to mind a dinner at a Dagstuhl seminar in the summer of 2019 (*). It's been a while now, so I hope my memory doesn't fail me too badly. Mark Guzdial was talking about a Pharo MOOC he had recently completed and how he was thinking of using the language to implement a piece of software for his new research group at Michigan, or perhaps a class he was teaching in the fall. If I recall correctly, he was torn between using Pharo and... JavaScript. He laid out some of the pros and cons of each, with JavaScript winning out on several pragmatic criteria, but his heart was clearly with Pharo. Shriram Krishnamurthi gently encouraged Mark to follow his heart: programming should be joyful, and programming languages allow us to build in languages that give us enjoyment. I seconded the (e)motion.

And here I sit mulling a similar choice.

Maybe I can make this a two-language year.

~~~~~

(*) Argh! I never properly blogged about about this seminar, on the interplay between notional machines and programming language semantics, or the experience of visiting Europe for the first time. I did write one post that mentioned Dagstuhl, Paris, and Montenegro, with an expressed hope to write more. Anything I write now will be filtered through two and a half years of fuzzy memory, but it may be worth the time to get it down in writing before it's too late to remember anything useful. In the meantime: both the seminar and the vacation were wonderful! If you are ever invited to participate in a Dagstuhl seminar, consider accepting.


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

December 31, 2021 12:13 PM

An Experience Rewriting a Piece of Code as as Teaching Tool

Over the last four or five offerings of my compiler course, I have been making progress in how I teach code generation, with teams becoming increasingly successful at producing a working code generator. In the 2019 offering, students asked a few new questions about some low-level mechanical issues in the run-time system. So I whipped up a simple one the night before class, both to refamiliarize myself with the issues and to serve as a potential example. It was not a great piece of software, but it was good enough for a quick in-class demo and as a seed for discussion.

Jump ahead to 2021. As I mentioned in my previous post, this fall's group had a lot more questions about assembly language, the run-time stack, activation records, and the like. When I pulled out my demo run-time system from last time, I found that it didn't help them as much as it had the previous group. The messiness of the code got in the way. Students couldn't see the bigger picture from the explanatory comments, and the code itself seemed opaque to them.

Working with a couple of students in particular, I began to refine the code. First, I commented the higher-level structure of generator more clearly. I then used those comments to reorganize the code bit, with the goal of improving the instructional presentation rather than the code's efficiency or compactness. I chose to leave some comments in rather than to factor out functions, because the students found the linear presentation easier to follow.

Finally, I refined some sections of the code and rewrote others entirely, to make them clearer. At this point, I did extract a helper function or two in an attempty not to obscure the story the program was telling with low-level details.

I worked through two iterations of this process: comment, reorganize, rewrite. At the end, I had a piece of code that is pretty good, and one that is on the student's path to a full code generator.

Of course, I could have designed my software up front and proceeded more carefully as I wrote this code. I mean, professionals and academics understand compiler construction pretty well. The result might well have been a better example of what the run-time generator should look like when students are done.

But I don't think that would have been as helpful to most members of my class. This process was much more like how my students program, and how many of us program, frankly, when we are first learning a new domain. Following this process, and working in direct response to questions students had as we discussed the code, gave me insights into some of the challenges they encounter in my course, including tracking register usage and seeing how the calling and return sequences interact. I teach these ideas in class, but my students were seeing that material as too abstract. They couldn't make the leap to code quite as easily as I had hoped; they were working concretely from the start.

In the end, I ended up with both a piece of code I like and a better handle on how my students approach the compiler project. In terms of outcomes assessment, this experience gives me some concrete ideas for improving the prerequisite courses students take before my course, such as computer organization. More immediately, it helps me improve the instruction in my own course. I have some ideas about how I can reorganize my code generator units and how I might simplify some of my pedagogical material. This may lead to a bigger redesign of the course in a coming semester.

I must admit: I had a lot of fun writing this code -- and revising and improving it! One bit of good news from the experience is that the advice I give in class is pretty good. If they follow my practical suggestions for writing their code, they can be successful. What needs improvement now is finding ways for students to have the relevant bits of advice at hand when they need them. Concrete advice that gets separated from concrete practice tends to get lost in the wind.

Finally, this experience reminded me first hand that the compiler project is indeed a challenge. It's fun, but it's a challenge, especially for undergrads attempting to write their first large piece of software as part of a team. There may be ways I can better help them to succeed.


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

December 28, 2021 5:31 PM

Thinking Back on My Compiler Course This Fall

Well, fall semester really got away from me quickly. It seems not long ago that I wrote of launching the course with a renewed mindset of "compilers for the masses, not compilers for compiler people". I'm not sure how well that went this time, as many students came into the course with less understanding of the underlying machine model and assembly language than ever before. As a result, many of them ended up stressing over low-level implementation details while shoring up that knowledge than thinking about some of the higher-level software engineering ideas. I spent more time this semester working with more teams to help them understand parsing rules, semantic actions, and activation records than in anytime I can remember.

I suspect that the students' programming maturity and state of knowledge at the start of the course are in large part a result of experiencing the previous two and a half semesters under the damper of the pandemic. Some classes were online, others were hybrid, and all were affected by mitigation efforts, doubt, and stress. Students and professors alike faced these effects, me included, and while everyone has been doing the best they could under the circumstances, sometimes the best we can do comes up a little short.

At the beginning of the course, I wrote about a particular uncertainty raised by the preceding pandemic semesters: how isolation and the interruption of regular life had reduced the chances for students to make friends in the major and to build up personal and professional connections with their classmates. I underestimated, I think, the effect that the previous year and a half would have on learning outcomes in our courses.

The effect on project teams themselves turned out to be a mixed bag. Three of the five teams worked pretty well together, even if one of the teammates was unable to contribute equally to the project. That's pretty typical. Two other teams encountered more serious difficulties working together effectively. Difficulties derailed one project that got off to an outstanding start, and the second ended up being a one-person show (a very impressive one-person show, in fact). In retrospect, many of these challenges can be traced back to problems some students had with content: they found themselves falling farther behind their teammates and responded by withdrawing from group work. The result is a bad experience for those still plugging along.

That's perhaps too many words about the difficulties. Several teams seemed to have pretty typical experiences working one another, even though they didn't really know each other before working together.

The combination of some students struggling with course content and some struggling with collaboration led to mixed bag of results. Two teams produced working compilers that handled essentially all language features correctly, or nearly so. That's pretty typical for a five-team semester. One team produced an incomplete system, but one they could be proud of after working pretty hard the entire semester. That's typical, too.

Two teams produced systems without code generators beyond a rudimentary run-time system. That's a bit unusual. These teams were disappointed because they had set much higher goals for themselves. Many of these students were taking heavy course and research loads and, unfortunately, all that work eventually overwhelmed them. I think I felt as bad for them as they did, knowing what they might have accomplished with a more forgiving schedule. I do hope they found some value in the course and will be able to look back on the experience as worthwhile. They learned a lot about working on a big project, and perhaps about themselves.

What about me? A few weeks into the course, I declared that I was programming like a student again, trying to implement the full compiler project I set before my students. Like many of my students, I accomplished some of my goals and fell short when outside obstacles got in the way. One the front end, my scanner is in great shape, while my parser is correct but in need of some refactoring. At that point in the semester, I got busy both with department duties and with working one on one with the teams, and my productivity dropped off.

I did implement a solid run-time system, one I am rather happy with. My work on it came directly out of answering students' questions about code generation and working with them to investigate and debug their programs. I'll have more to say about my run-time system in the next post.

So, my latest compiler course is in the books. All in all, my students and I did about as well as we could under the circumstances. There is still great magic in watching a team's compiler generate an executable, then running that executable on an input that produces tens of thousands of activation records and executes several million lines of assembly. The best we can do is often quite good enough.


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

November 28, 2021 10:35 AM

Students Need to Develop Microskills, Too

Yesterday someone retweeted this message from Hillel Wayne into my timeline:

A surprising and undervalued aspect of mastery comes from narrow-scope "microskills". In software, these would be things like

- Python list comprehensions
- Grep flags
- Debugging specific error messages
- Using a window manager

We can, and should, do targeted training.

Later in the short thread, Hillel says something that brought my students to mind:

In other words, the high level thinking is the difference between a task being possible and impossible, but the microskills are the difference between a task being 20 minutes and six hours. That's why it can take us days to find the right one-liner.

Some students love to program and look for every opportunity to write code. These students develop a satchelful of microskills, usually far behind what we could every teach them or expose them to in class. They tend to do fine on the programming assignments we give in class.

Other students complain that a programming assignment I gave them, intended as a one-hour practice session, took them eight or ten hours. My first reaction is usually to encourage them never to spin their wheels that long without asking me a question. I want them to develop grit, but usually that kind of wheel spinning is a sign that they may be missing a key idea or piece of information. I'd like to help them get moving sooner.

There is another reason, though, that many of these students spin their wheels. For a variety of reasons, they program only when they are required by a class. They are ambivalent about programming, either because they don't find it as interesting as their peers or because they don't enjoy the grind of working in the trenches yet. I say "yet" because one of the ways we all come to enjoy the grind is... to grind away! That's how we develop the microskills Hillel is talking about, which turn a six-hour task into a 20-minute task, or a disappointing one-hour experience with a homework problem into a five-minute joy.

Students who have yet to experience the power of microskills are prone to underestimate their value. That makes it less enjoyable to practice programming, which makes it hard to develop new skills. It's a self-reinforcing loop, and not the kind we want to encourage in our students.

Even after all these years in the classroom, I still struggle to find ways to help my students practice programming skills in a steady, reliable way. Designing engaging problems to work on helps. So does letting students choose the problems they work on, which works better in some courses than others. Ultimately, though, I think what works best is to develop as much of a personal relationship with each student as possible. This creates a condition in which they are more inclined to ask for help when they need it and to trust suggestions from that sound a little crazy to the beginner's mind.

I am teaching my compiler development course this semester, which means that I am working with students near the end of their time with us, whose habits are deeply ingrained from previous courses. The ones who don't already possess a few of the microskills they need are struggling as the task of writing a parser or semantic checker or code generator stretches out like an endless desert before them.

Next semester, I teach my programming languages course and have the joy of introducing my students to Racket and functional programming. This essay me already thinking of how I can help my students develop some of the microskills they will want and need in the course and beyond. Perhaps a more explicit focus early on the use Dr. Racket to create, run, test, and debug code can set them up for a more enjoyable experience later in the course -- and help put them on a virtuous self-reinforcing loop developing skills and using them to enjoy the next bit of learning they do.


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

October 28, 2021 3:52 PM

A Few Quotes from "The Triggering Town"

A couple of weeks back, I saw an article in which Malcom Gladwell noted that he did not know The Triggering Town, a slim book of essays by poet Richard Hugo. I was fortunate to hear about Hugo many years ago from software guru Richard Gabriel, who is also a working poet. It had been fifteen years or more since I'd read The Triggering Town, so I stopped into the library on my way home one day and picked it up. I enjoyed it the second time around as much as the first.

I frequently make notes of passages to save. Here are five from this reading.

Actually, the hard work you do on one poem is put in on all poems. The hard work on the first poem is responsible for the sudden ease of the second. If you just sit around waiting for the easy ones, nothing will come. Get to work.

That advice works for budding software developers, too.

Emotional honesty is a rare thing in the academic world or anywhere else for that matter, and nothing is more prized by good students.

Emotion plays a much smaller role in programming than in writing poetry. Teaching, though, is deeply personal, even in a technical discipline. All students value emotional honesty, and profs who struggle to be open usually struggle making connections to their students.

Side note: Teachers, like policemen, firemen, and service personnel, should be able to retire after twenty years with full pension. Our risks may be different, but they are real. In twenty years most teachers have given their best.

This is a teacher speaking, so take the recommendation with caution. But more than twenty years into this game, I know exactly what Hugo means.

Whatever, by now, I was old enough to know explanations are usually wrong. We never quite understand and we can't quite explain.

Yet we keep trying. Humans are an optimistic animal, which is one of the reasons we find them so endearing.

... at least for me, what does turn me on lies in a region of myself that could not be changed by the nature of my employment. But it seems important (to me even gratifying) that the same region lies untouched and unchanged in a lot of people, and in my innocent way I wonder if it is reason for hope. Hope for what? I don't know. Maybe hope that humanity will always survive civilization.

This paragraph comes on the last page of the book and expresses one of the core tenets of Hugo's view of poetry and poets. He fought in World War 2 as a young man, then worked in a Boeing factory for 15-20 years, and then became an English professor at a university. No matter the day job, he was always a poet. I have never been a poet, but I know quite well the region of which he speaks.

Also: I love the sentence, "Maybe hope that humanity will always survive civilization."


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

October 02, 2021 5:37 PM

Strange Loop 2: Day Two

I am usually tired on the second day of a conference, and today was no exception. But the day started and ended with talks that kept my brain alive.

• "Poems in an Accidental Language" by Kate Compton -- Okay, so that was a Strange Loop keynote. When the video goes live on YouTube, watch it. I may blog more about the talk later, but for now know only that it included:

  • "Evenings of Recreational Ontology" (I also learned about Google Sheet parties)
  • "fitting an octopus into an ontology"
  • "Contemplate the universe, and write an API for it."
Like I said, go watch this talk!

• Quantum computing is one of those technical areas I know very little about, maybe the equivalent of a 30-minute pitch talk. I've never been super-interested, but some of my students are. So I attended "Practical Quantum Computing Today" to see what's up these days. I'm still not interested in putting much of my time into quantum computing, but now I'm better informed.

• Before my lunch walk, I attended a non-technical talk on "tech-enabled crisis response". Emma Ferguson and Colin Schimmelfing reported on their experience doing something I'd like to be able to do: spin up a short-lived project to meet a critical need, using mostly free or open-source tools. For three months early in the COVID pandemic, their project helped deliver ~950,000 protective masks from 7,000 donors to 6,000 healthcare workers. They didn't invent new tech; they used existing tools and occasionally wrote some code to connect such tools.

My favorite quote from the talk came when Ferguson related the team's realization that they had grown too big for the default limits on Google Sheets and Gmail. "We thought, 'Let's just pay Google.' We tried. We tried. But we couldn't figure it out." So they built their own tool. It is good to be a programmer.

• After lunch, Will Crichton live-coded a simple API in Rust, using traits (Rust's version of interfaces) and aggressive types. He delivered almost his entire talk within emacs, including an ASCII art opening slide. It almost felt like I was back in grad school!

• In "Remote Workstations for Discerning Artists", Michelle Brenner from Netflix described the company's cloud-based infrastructure for the workstations used by the company's artists and project managers. This is one of those areas that is simply outside my experience, so I learned a bit. At the top level, though, the story is familiar: the scale of Netflix's goals requires enabling artists to work wherever they are, whenever they are; the pandemic accelerated a process that was already underway.

• Eric Gade gave another talk in the long tradition of Alan Kay and a bigger vision for computing. "Authorship Environments: In Search of the 'Personal' in Personal Computing" started by deconstructing Steve Jobs's "bicycle for the mind" metaphor (he's not a fan of what most people take as the meaning) and then moved onto the idea of personal computing as literacy: a new level at which to interrogate ideas, including one's own.

This talk included several inspirational quotes. My favorite was was from Adele Goldberg:

There's all these layers in everything we do... We have to learn how to peel.
(I have long admired Goldberg and her work. See this post from Ada Lovelace Day 2009 for a few of my thoughts.)

As with most talks in this genre, I left feeling like there is so much more to be done, but frustrated at not knowing how to do it. We still haven't found a way to reach a wide audience with the empowering idea that there is more to computing than typing into a Google doc or clicking in a web browser.

• The closing keynote was delivered by Will Byrd. "Strange Dreams of Stranger Loops" took Douglas Hofstadter's Gödel, Escher, Bach as its inspiration, fitting both for the conference and for Byrd's longstanding explorations of relational programming. His focus today: generating quines in mini-Kanren, and discussing how quines enable us to think about programs, interpreters, and the strange loops at the heart of GEB.

As with the opening keynote I may blog more about this talk later. For now I give you two fun items:

  • Byrd expressed his thanks to D((a(d|n))oug), a regular expression that matches on Byrd (his father), Friedman (his academic mentor), and Hofstadter (his intellectual inspiration).
  • While preparing his keynote, Byrd clains to have suffered from UDIS: Unintended Doug Intimidation Syndrome. Hofstader is so cultured, so well-read, and so deep a thinker, how can the rest of us hope to contribute?
Rest assured: Byrd delivered. A great talk, as always.

Strange Loop 2021 has ended. I "hit the road" by walking upstairs to make dinner with my wife.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Personal, Software Development

September 27, 2021 2:04 PM

Programming Like a Student Again

For the first time in many years, I got the urge this fall to implement the compiler project I set before my students.

I've written here about this course many times over the years. It serves students interested in programming languages and compilers as well as students looking for a big project course and students looking for a major elective. Students implement a compiler for a small language by hand in teams of 2-5, depending on the source language and the particular group of people in the course.

Having written small compilers like this many times, I don't always implement the entire project each offering. That would not be a wise use of my time most semesters. Instead, when something comes up in class, I will whip up a quick scanner or type checker or whatever so that we can explore an idea. In recent years, the bits I've written have tended to be on the backend, where I have more room to learn.

But this fall, I felt the tug to go all in.

I created a new source language for the class this summer, which I call Twine. Much of its concrete syntax was inspired by SISAL, a general-purpose, single-assignment functional language with implicit parallelism and efficient array handling. SISAL was designed in the mid-1980s to be a high-level language for large numerical programs, to be run on a variety of multiprocessors. With advances in multiprocessors and parallel processors, SISAL is well suited for modern computation. Of course, it contains many features beyond what we can implement in a one-semester compiler course where students implement all of their own machinery. Twine is essentially a subset of SISAL, with a few additions and modifications aimed at making the language more suitable for our undergraduate course.

the logo of the Twine programming language

(Whence the name "Twine"? The name of SISAL comes from the standard Unix word list. It was chosen because it contains the phrase "sal", which is an acronym for "single assignment language". The word "sisal" itself is the name of a flowering plant native to southern Mexico but widely cultivated around the world. Its leaves are crushed to extract a fiber that is used to create rope and twine. So, just as the sisal plant is used to create twine, the SISAL programming language was used to create the Twine programming language.)

With new surface elements, the idea of implementing a new front end appealed to me. Besides, the experience of implementing a complete system feels different than implementing a one-off component... That's one of the things we want our students to experience in our project courses! After eighteen months of weirdness and upheaval at school and in the world, I craved that sort of connection to some code. So here I am.

Knocking out a scanner in my free time over the last week and getting started on my parser has been fun. It has also reminded me how the choice of programming language affects how I think about the code I am writing.

I decided to implement in Python, the language most of my student teams are using this fall, so that I might have recent experience with specific issues they encounter. I'd forgotten just how list-y Python is. Whenever I look at Python code on the web, it seems that everything is a list or a dictionary. The path of least resistance flows that way... If I walk that path, I soon find myself with a list of lists of lists, and my brain is swimming in indices. Using dictionaries replaces integer indices with keys of other types, but the conceptual jumble remains.

It did not take me long to appreciate anew why I like to work with objects. They give me the linguistic layers I need to think about my code independent of languages primitives. I know, I know, I can achieve the same thing with algebraic types and layers of function definitions. However, my mind seems to work on a wavelength where data encapsulation and abstract messages go together. Blame Smalltalk for ruining me, or enlightening me, whichever your stance.

Python provides a little extra friction to classes and objects that seems to interrupt my flow occasionally. For a few minutes this week, I felt myself missing Java and wondering if I ought to have chosen it for the project instead of Python. I used to program in Java every day, and this was the first time in a long while that I felt the pull back. After programming so much in Racket the last decade, though, the wordiness of Java keeps me away. Alas, Python is not the answer. Maybe I'm ready to go deep on a new language, but which one? OOP doesn't seem to be in vogue these days. Maybe I need to return to Ruby or Smalltalk.

For now I will live with OOP in Python and see whether its other charms can compensate. Living with Python's constraints shows up as a feature of another choice I made for this project: to let pycodestyle tell me how to format my code. This is an obstacle for any programmer who is as idiosyncratic as I am. After a few rounds of reformatting my code, though, I am finding surrender easier to accept. This has freed me to pay attention to more important matters, which is one of the keys ideas behind coding and style standards in the first place. But I am a slow learner.

It's been fun so far. I look forward to running Twine programs translated by my compiler in a few weeks! As long as I've been programming, I have never gotten over the thrill of watching my compiler I've written -- or any big program I've written -- do its thing. Great joy.


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

December 30, 2020 3:38 PM

That's a Shame

In the middle of an old post about computing an "impossible" integral, John Cook says:

In the artificial world of the calculus classroom, everything works out nicely. And this is a shame.

When I was a student, I probably took comfort in the fact that everything was supposed to work out nicely on the homework we did. There *was* a solution; I just had to find the pattern, or the key that turned the lock. I suspect that I was a good student largely because I was good at finding the patterns, the keys.

It wasn't until I got to grad school that things really changed, and even then course work was typically organized pretty neatly. Research in the lab was very different, of course, and that's where my old skills no longer served me so well.

In university programs in computer science, where many people first learn how to develop software, things tend to work out nicely. That is a shame, too. But it's a tough problem to solve.

In most courses, in particular introductory courses, we create assignments with that have "closed form" solutions, because we want students to practice a specific skill or learn a particular concept. Having a fixed target can be useful in achieving the desired outcomes, especially if we want to help students build confidence in their abilities.

It's important, though, that we eventually take off the training wheels and expose students to messier problems. That's where they have an opportunity to build other important skills they need for solving problems outside the classroom, which aren't designed by a benevolent instructor to have follow a pattern. As Cook says, neat problems can create a false impression that every problem has a simple solution.

Students who go on to use calculus for anything more than artificial homework problems may incorrectly assume they've done something wrong when they encounter an integral in the wild.

CS students need experience writing programs that solve messy problems. In more advanced courses, my colleagues and I all try to extend students' ability to solve less neatly-designed problems, with mixed results.

It's possible to design a coherent curriculum that exposes students to an increasingly messy set of problems, but I don't think many universities do this. One big problem is that doing so requires coordination across many courses, each of which has its own specific content outcomes. There's never enough time, it seems, to teach everything about, say, AI or databases, in the fifteen weeks available. It's easier to be sure that we cover another concept than it is to be sure students take a reliable step along the path from being able to solve elementary problems to being able to solve to the problems they'll find in the wild.

I face this set of competing forces every semester and do my best to strike a balance. It's never easy.

Courses that involve large systems projects are one place where students in my program have a chance to work on a real problem: writing a compiler, an embedded real-time system, or an AI-based system. These courses have closed form solutions of sorts, but the scale and complexity of the problems require students to do more than just apply formulas or find simple patterns.

Many students thrive in these settings. "Finally," they say, "this is a problem worth working on." These students will be fine when they graduate. Other students struggle when they have to do battle for the first time with an unruly language grammar or a set of fussy physical sensors. One of my challenges in my project course is to help this group of students move further along the path from "student doing homework" to "professional solving problems".

That would be a lot easier to do if we more reliably helped students take small steps along that path in their preceding courses. But that, as I've said, is difficult.

This post describes a problem in curriculum design without offering any solutions. I will think more about how I try to balance the forces between neat and messy in my courses, and then share some concrete ideas. If you have any approaches that have worked for you, or suggestions based on your experiences as a student, please email me or send me a message on Twitter. I'd love to learn how to do this better.

I've written a number of posts over the years that circle around this problem in curriculum and instruction. Here are three:

I'm re-reading these to see if past me has any ideas for present-day me. Perhaps you will find them interesting, too.


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

December 27, 2020 10:10 AM

What Paul McCartney Can Teach Us About Software

From Sixty-Four Reasons to Celebrate Paul McCartney, this bit of wisdom that will sound familiar to programmers:

On one of the tapes of studio chatter at Abbey Road you can hear McCartney saying, of something they're working on, "It's complicated now. If we can get it simpler, and then complicate it where it needs to be complicated..."

People talk a lot about making software as simple as possible. The truth is, software sometimes has to be complicated. Some programs perform complex tasks. More importantly, programs these days often interact in complex environments with a lot of dissimilar, distributed components. We cannot avoid complexity.

As McCartney knows about music, the key is to make things as simple as can be and introduce complexity only where it is essential. Programmers face three challenges in this regard:

  • learning how to simplify code,
  • learning how to add complexity in a minimal, contained fashion, and
  • learning how to recognize the subtle boundary between essential simplicity and essential complexity.
I almost said that new programmers face those challenges, but after many years of programming, I feel like I'm still learning how to do all three of these things. I suspect other experienced programmers are still learning, too.

On an unrelated note, another passage in this article spoke to me personally as a programmer. While discussing McCartney's propensity to try new things and to release everything, good and bad, it refers to some of the songs on his most recent album (at that time) as enthusiastically executed misjudgments. I empathize with McCartney. My hard drive is littered with enthusiastically executed misjudgments. And I've never written the software equivalent of "Hey Jude".

McCartney just released a new album this month at the age of 78. The third album in a trilogy conceived and begun in 1970, it has already gone to #1 in three countries. He continues to write, record, and release, and collaborates frequently with today's artists. I can only hope to be enthusiastically producing software, and in tune with the modern tech world, when I am his age.


Posted by Eugene Wallingford | Permalink | Categories: General, Software Development

September 22, 2020 4:09 PM

Time Spent Programming Is Often Time Well Spent

This.

Was the time I spent writing my RSS scripts more than the time I would now spend thinking about the "best" RSS aggregator and reader? Doesn't matter. I enjoyed writing the scripts. I learned new things and got satisfaction out of seeing them run correctly. I get nothing like that out of comparing apps and services.

I concur so strongly not only because he writes about RSS, which I'm on record as supporting and using. I enjoy rolling my own simple software in almost any domain. Simple has a lot of advantages. Under my control has a lot of advantages. But the biggest advantage echoes what Dr. Drang says: Programming is often more fun than the alternative uses of my time.

I program because I like to, and because I can.


Posted by Eugene Wallingford | Permalink | Categories: Personal, Software Development

September 18, 2020 2:50 PM

If You Want to Create Greatness, Encourage Everyone

I read two passages in the last few days that echo one another. First, I read this from Wallace Shawn, in a Paris Review interview:

But my God, without writers, humanity might be trapped in a swamp of idiotic, unchanging provincial clichés. Yes, there are writers who merely reinforce people's complacency, but a writer like Rachel Carson inspired the activism of millions, and writers like Lady Murasaki, Milton, and Joyce have reordered people's brains! And for any writers to exist at all, there must surely be a tradition of writing. Maybe in order for one valuable writer to exist, there must be a hundred others who aren't valuable at all, but it isn't possible at any given moment for anyone to be sure who the valuable one is.

Then, in his response to Marc Andreessen's "It's Time to Build", Tanner Greer writes:

To consistently create brilliant poets, you need a society awash in mediocre, even tawdry poetry. Brilliant minds will find their way towards poem writing when poem writing and poem reading is the thing that people do.

I once blogged briefly about The Art of Fear tells the story of an artist sketching hundreds of roosters, which laid the foundation for creating a single sketch for his client. For us as individuals, this means that "talent is rarely distinguishable, over the long run, from perseverance and lots of hard work." As Richard Gabriel often says, "Talent determines only how fast you get good, not how good you get". Volume creates the conditions under which quality can appear.

Shawn and Greer remind us that the same dynamic applies at the scale of a culture. A community that produces many writers has a better chance to produce great writers. When the community values writers, it increases the chances that someone will do the work necessary to becoming a writer. The best way to produce a lot of writers is to have a tradition that welcomes, even encourages, all members of the community to write, even if they aren't great.

The same applies to other forms of achievement, too. In particular, I think it applies to programming.


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

August 22, 2020 4:09 PM

Learning Something You Thought You Already Knew

Sandi Metz's latest newsletter is about the heuristic not to name a class after the design pattern it implements. Actually, it's about a case in which Metz wanted to name a class after the pattern it implements in her code and then realized what she had done. She decided that she either needed to have a better reason for doing it than "because it just felt right" or she needed practice what she preaches to the rest of us. What followed was some deep thinking about what makes the rule a good one to follow and her efforts to put her conclusions in writing for the benefit of her readers.

I recognize with Metz's sense of discomfort at breaking a rule when it feels right and her need to step back and understand the rule at a deeper level. Between her set up and her explanation, she writes:

I've built a newsletter around this rule not only because I believe that it's useful, but also because my initial attempts to explain it exposed deep holes in my understanding. This was a revelation. Had I not been writing a book, I might have hand-waved around these gaps in my knowledge forever.

People sometimes say, "If you you really want to understand something, teach it to others." Metz's story is a great example of why this is really true. I mean, sure, you can learn any new area and then benefit from explaining it to someone else. Processing knowledge and putting it in your own words helps to consolidate knowledge at the surface. But the real learning comes when you find yourself in a situation where you realize there's something you've taken for granted for months or for years, something you thought you knew, but suddenly you sense a deep hole lying under the surface of that supposed understanding. "I just know breaking the rule is the right thing to do here, but... but..."

I've been teaching long enough to have had this experience many times in many courses, covering many areas of knowledge. It can be terrifying, at least momentarily. The temptation to wave my hands and hurry past a student's question is enormous. To learn from teaching in these moments requires humility, self-awareness, and a willingness to think and work until you break through to that deeper understanding. Learning from these moments is what sets the best teachers and writers apart from the rest of us.

As you might guess from Metz's reaction to her conundrum, she's a pretty good teacher and writer. The story in the newsletter is from the new edition of her book "99 Bottles of OOP", which is now available. I enjoyed the first edition of "99 Bottles" and found it useful in my own teaching. It sounds like the second edition will be more than a cleanup; it will have a few twists that make it a better book.

I'm teaching our database systems course for the first time ever this fall. This is a brand new prep for me: I've never taught a database course before, anywhere. There are so many holes in my understanding, places where I've internalized good practices but don't grok them in the way an expert does. I hope I have enough humility and self-awareness this semester to do my students right.


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

July 16, 2020 10:47 AM

Dreaming in Git

I recently read a Five Books interview about the best books on philosophical wonder. One of the books recommended by philosopher Eric Schwitzgebel was Diaspora, a science fiction novel by Greg Egan I've never read. The story unfolds in a world where people are able to destroy their physical bodies to upload themselves into computers. Unsurprisingly, this leads to some fascinating philosophical possibilities:

Well, for one thing you could duplicate yourself. You could back yourself up. Multiple times.

And then have divergent lives, as it were, in parallel but diverging.

Yes, and then there'd be the question, "do you want to merge back together with the person you diverged from?"

Egan wrote Diaspora before the heyday of distributed version control, before darcs and mercurial and git. With distributed VCS, a person could checkout a new personality, or change branches and be a different person every day. We could run diffs to figure out what makes one version of a self so different from another. If things start going too wrong, we could always revert to an earlier version of ourselves and try again. And all of this could happen with copies of the software -- ourselves -- running in parallel somewhere in the world.

And then there's Git. Imagine writing such a story now, with Git's complex model of versioning and prodigious set of commands and flags. Not only could people branch and merge, checkout and diff... A person could try something new without ever committing changes to the repository. We'd have to figure out what it means to push origin or reset --hard HEAD. We'd be able to rewrite history by rebasing, amending, and squashing. A Git guru can surely explain why we'd need to --force-with-lease or --unset-upstream, but even I can imagine the delightful possibilities of git stash in my personal improvement plan.

Perhaps the final complication in our novel would involve a merge so complex that we need a third-party diff tool to help us put our desired self back together. Alas, a Python library or Ruby gem required by the tool has gone stale and breaks an upgrade. Our hero must find a solution somewhere in her tree of blobs, or be doomed to live a forever splintered life.

If you ever see a book named Dreaming in Git or Bug Report on an airport bookstore's shelves, take a look. Perhaps I will have written the first of my Git fantasies.


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

June 17, 2020 3:53 PM

Doing Concatenative Programming in a Spreadsheet

a humble spreadsheet cell

It's been a long time since I was excited by a new piece of software the way I was excited by Loglo, Avi Bryant's new creation. Loglo is "LOGO for the Glowforge", an experimental programming environment for creating SVG images. That's not a problem I need to solve, but the way Loglo works drew me in immediately. It consists of a stack programming language and a set of primitives for describing vector graphics, integrated into a spreadsheet interface. It's the use of a stack language to program a spreadsheet that excites me so much.

Actually, it's the reverse relationship that really excites me: using a spreadsheet to build and visualize a stack-based program. Long-time readers know that I am interested in this style of programming (see Summer of Joy for a post from last year) and sometimes introduce it in my programming languages course. Students understand small examples easily enough, but they usually find it hard to grok larger programs and to fully appreciate how typing in such a language can work. How might Loglo help?

In Loglo, a cell can refer to the values produced by other cells in the familiar spreadsheet way, with an absolute address such as "a1" or "f2". But Loglo cells have two other ways to refer to other cell's values. First, any cell can access the value produced by the cell to its left implicitly, because Loglo leaves the result of a cell's computation sitting on top of the stack. Second, a cell can access the value produced by the cell above it by using the special variable "^". These last two features strike me as a useful way for programmers to see their computations grow over time, which can be an even more powerful mode of interaction for beginners who are learning this programming style.

Stack-oriented programming of this sort is concatenative: programs are created by juxtaposing other programs, with a stack of values implicitly available to every operator. Loglo uses the stack as leverage to enable programmers to build images incrementally, cell by cell and row by row, referring to values on the stack as well as to predecessor cells. The programmer can see in a cell the value produced by a cumulative bit of code that includes new code in the cell itself. Reading Bryant's description of programming in Loglo, it's easy to see how this can be helpful when building images. I think my students might find it helpful when learning how to write concatenative programs or learning how types and programs work in a concatenative language.

For example, here is a concatenative program that works in Loglo as well as other stack-based languages such as Forth and Joy:

 2 3 + 5 * 2 + 6 / 3 /

Loglo tells us that it computes the value 1.5:

a stack program in Loglo

This program consists of eleven tokens, each of which is a program in its own right. More interestingly, we can partition this program into smaller units by taking any subsequences of the program:

 2 3 + 5 *   2 + 6 /   3 /
 ---------   -------   ---
These are the programs in cells A1, B1, and C1 of our spreadsheet. The first computes 25, the second uses that value to compute 4.5, and the third uses the 4.5 to compute 1.5. Notice that the programs in cells B1 and C1 require an extra value to do their jobs. They are like functions of one argument. Rather than pass an argument to the function, Loglo allows it to read a value from the stack, produced by the cell to its left.

a partial function in Loglo

By making the intermediate results visible to the programmer, this interface might help programmers better see how pieces of a concatenative program work and learn what the type of a program fragment such as 2 + 6 / (in cell B1 above) or 3 / is. Allowing locally-relative references on a new row will, as Avi points out, enable an incremental programming style in which the programmer uses a transformation computed in one cell as the source for a parameterized version of the transformation in the cell below. This can give the novice concatenative programmer an interactive experience more supportive than the usual REPL. And Loglo is a spreadsheet, so changes in one cell percolate throughout the sheet on each update!

Am I the only one who thinks this could be a really cool environment for programmers to learn and practice this style of programming?

Teaching concatenative programming isn't a primary task in my courses, so I've never taken the time to focus on a pedagogical environment for the style. I'm grateful to Avi for demonstrating a spreadsheet model for stack programs and stimulating me to think more about it.

For now, I'll play with Loglo as much as time permits and think more about its use, or use of a tool like it, in my courses. There are couple of features I'll have to get used to. For one, it seems that a cell can access only one item left on the stack by its left neighbor, which limits the kind of partial functions we can write into cells. Another is that named functions such as rotate push themselves onto the stack by default and thus require a ! to apply them, whereas operators such as + evaluate by default and thus require quotation in a {} block to defer execution. (I have an academic's fondness for overarching simplicity.) Fortunately, these are the sorts of features one gets used to whenever learning a new language. They are part of the fun.

Thinking beyond Loglo, I can imagine implementing an IDE like this for my students that provides features that Loglo's use cases don't require. For example, it would be cool to enable the programmer to ctrl-click on a cell to see the type of the program it contains, as well as an option to see the cumulative type along the row or built on a cell referenced from above. There is much fun to be had here.

To me, one sign of a really interesting project is how many tangential ideas flow out of it. For me, Loglo is teeming with ideas, and I'm not even in its target demographic. So, kudos to Avi!

Now, back to administrivia and that database course...


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

June 11, 2020 1:02 PM

Persistence Wins, Even For Someone Like You

There's value to going into a field that you find difficult to grasp, as long as you're willing to be persistent. Even better, others can benefit from your persistence, too.

In an old essay, James Propp notes that working in a field where you lack intuition can "impart a useful freedom from prejudice". Even better...

... there's value in going into a field that you find difficult to grasp, as long as you're willing to be really persistent, because if you find a different way to think about things, something that works even for someone like you, chances are that other people will find it useful too.

This reminded me of a passage in Bob Nystroms's post about his new book, Crafting Interpreters. Nystrom took a long time to finish the book in large part because he wanted the interpreter at the end of each chapter to compile and run, while at the same time growing into the interpreter discussed in the next chapter. But that wasn't the only reason:

I made this problem harder for myself because of the meta-goal I had. One reason I didn't get into languages until later in my career was because I was intimidated by the reputation compilers have as being only for hardcore computer science wizard types. I'm a college dropout, so I felt I wasn't smart enough, or at least wasn't educated enough to hack it. Eventually I discovered that those barriers existed only in my mind and that anyone can learn this.

Some students avoid my compilers course because they assume it must be difficult, or because friends said they found it difficult. Even though they are CS majors, they think of themselves as average programmers, not "hardcore computer science wizard types". But regardless of the caliber of the student at the time they start the course, the best predictor of success in writing a working compiler is persistence. The students who plug away, working regularly throughout the two-week stages and across the entire project, are usually the ones who finish successfully.

One of my great pleasures as a prof is seeing the pride in the faces of students who demo a working compiler at the end of the semester, especially in the faces of the students who began the course concerned that they couldn't hack it.

As Propp points out in his essay, this sort of persistence can pay off for others, too. When you have to work hard to grasp an idea or to make something, you sometimes find a different way to think about things, and this can help others who are struggling. One of my jobs as a teacher is to help students understand new ideas and use new techniques. That job is usually made easier when I've had to work persistently to understand the idea myself, or to find a better way to help the students who teach me the ways in which they struggle.

In Nystrom's case, his hard work to master a field he didn't grasp immediately pays of for his readers. I've been following the growth of Crafting Interpreters over time, reading chapters in depth whenever I was able. Those chapters were uniformly easy to read, easy to follow, and entertaining. They have me thinking about ways to teach my own course differently, which is probably the highest praise I can give as a teacher. Now I need to go back and read the entire book and learn some more.

Teaching well enough that students grasp what they thought was not graspable and do what they thought was not doable is a constant goal, rarely achieved. It's always a work in progress. I have to keep plugging away.


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

May 16, 2020 11:33 AM

Woz Sez: Take Some Time To Get To Know Your Program Better

Steve Wozniak in Founders at Work:

If you can just quickly whip something out and it's done, maybe it's time, once in a while, to think and think and think, "Can I make it better than it is, a little superior?" What that does is not necessarily make the product better in the end, but it brings you closer to the product, and your own head understands it better. Your neurons have gone through the code you wrote, or the circuits you designed, have gone through it more times, and it's just a little more solidly in your head and once in a while you'll wake up and say, "Oh my God, I just realized a bug that's in there, something I hadn't thought of."

Or, if you have to modify something, or add something new, you can do it very quickly when it's all in your head. You don't have to pull out the listing and find out where and maybe make a mistake. You don't make as many mistakes.

Many programmers know this feeling, of having a program in your head and moving in sync with it. When programs are small, it's easy for me to hold a program in my head. As it grows larger and spreads out over many functions, classes, and files, I have to live with it over an extended period of time. Taking one of Woz's dives into the just to work on it is a powerful way to refresh the feeling.

Beginning programmers have to learn this feeling, I think, and we should help them. In the beginning, my students know what it's like to have a program in their head all at once. The programs are small, and the new programmer has to pay attention to every detail. As programs grow, it becomes harder for them. They work locally to make little bits of code work, and suddenly they have a program that does fit naturally in their head. But they don't have the luxury of time to do what Woz suggests, because they are on to the next reading assignment, the next homework, the next class across campus.

One of the many reasons I like project courses such as my compiler course is that students live with the same code for an entire semester. Sure, they finish the scanner and move on to the parser, and then onto a type checker and a code generator, but they use their initial stages every day and live with the decisions they made. It's not uncommon for a student to tell me 1/2 or 3/4 of the way through the course, "I was looking at our scanner (or parser) the other day, and now I understand why we were having that problem I told you about. I'm going to fix it over Thanksgiving break."

In my programming languages course, we close with a three week three assignment project building an interpreter. I love when a student submitting on Part 3 says, "Hey, I just noticed that some parts of Part 2 could be better. I hope you don't mind that I improved that, too." Um, no. No, I don't mind at all. They get it.

It's easy to shortchange our students with too many small projects. I like most of my courses to have at least some code grow over the course of the semester. Students may not have the luxury of a lot of free time, but at least they work in proximity to their old code for a while. Serendipity may strike if we create the right conditions for it.

I have already begun to think about how I can foster this in my new course this fall. I hope to design it into the course upfront.


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

May 10, 2020 2:16 PM

Software Can Make You Feel Alive, or It Can Make You Feel Dead

This week I read one of Craig Mod's old essays and found a great line, one that everyone who writes programs for other people should keep front of mind:

When it comes to software that people live in all day long, a 3% increase in fun should not be dismissed.

Working hard to squeeze a bit more speed out of a program, or to create even a marginally better interaction experience, can make a huge difference to someone who uses that program everyday. Some people spend most of their professional days inside one or two pieces of software, which accentuates further the human value of Mod's three percent. With shelter-in-place and work-from-home the norm for so many people these days, we face a secondary crisis of software that is no fun.

I was probably more sensitive than usual to Mod's sentiment when I read it... This week I used Blackboard for the first time, at least my first extended usage. The problem is not Blackboard, of course; I imagine that most commercial learning management systems are little fun to use. (What a depressing phrase "commercial learning management system" is.) And it's not just LMSes. We use various PeopleSoft "campus solutions" to run the academic, administrative, and financial operations on our campus. I always feel a little of my life drain away whenever I spend an hour or three clicking around and waiting inside this large and mostly functional labyrinth.

It says a lot that my first thought after downloading my final exams on Friday morning was, "I don't have to login to Blackboard again for a good long while. At least I have that going for me."

I had never used our LMS until this week, and then only to create a final exam that I could reliably time after being forced into remote teaching with little warning. If we are in this situation again in the fall, I plan to have an alternative solution in place. The programmer in me always feels an urge to roll my own when I encounter substandard software. Writing an entire LMS is not one of my life goals, so I'll just write the piece I need. That's more my style anyway.

Later the same morning, I saw this spirit of writing a better program in a context that made me even happier. The Friday of finals week is my department's biennial undergrad research day, when students present the results of their semester- or year-long projects. Rather than give up the tradition because we couldn't gather together in the usual way, we used Zoom. One student talked about alternative techniques for doing parallel programming in Python, and another presented empirical analysis of using IR beacons for localization of FIRST Lego League robots. Fun stuff.

The third presentation of the morning was by a CS major with a history minor, who had observed how history profs' lectures are limited by the tools they had available. The solution? Write better presentation software!

As I watched this talk, I was proud of the student, whom I'd had in class and gotten to know a bit. But I was also proud of whatever influence our program had on his design skills, programming skills, and thinking. This project, I thought, is a demonstration of one thing every CS student should learn: We can make the tools we want to use.

This talk also taught me something non-technical: Every CS research talk should include maps of Italy from the 1300s. Don't dismiss 3% increases in fun wherever they can be made.


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

April 04, 2020 11:37 AM

Is the Magic Gone?

This passage from Remembering the LAN recalls an earlier time that feels familiar:

My father, a general practitioner, used this infrastructure of cheap 286s, 386s, and 486s (with three expensive laser printers) to write the medical record software for the business. It was used by a dozen doctors, a nurse, and receptionist. ...
The business story is even more astonishing. Here is a non-programming professional, who was able to build the software to run their small business in between shifts at their day job using skills learned from a book.

I wonder how many hobbyist programmers and side-hustle programmers of this sort there are today. Does programming attract people the way it did in the '70s or '80s? Life is so much easier than typing programs out of Byte or designing your own BASIC interpreter from scratch. So many great projects out on Github and the rest of the web to clone, mimic, adapt. I occasionally hear a student talking about their own projects in this way, but it's rare.

As Crawshaw points out toward the end of his post, the world in which we program now is much more complex. It takes a lot more gumption to get started with projects that feel modern:

So much of programming today is busywork, or playing defense against a raging internet. You can do so much more, but the activation energy required to start writing fun collaborative software is so much higher you end up using some half-baked SaaS instead.

I am not a great example of this phenomenon -- Crawshaw and his dad did much more -- but even today I like to roll my own, just for me. I use a simple accounting system I've been slowly evolving for a decade, and I've cobbled together bits and pieces of my own tax software, not an integrated system, just what I need to scratch an itch each year. Then there are all the short programs and scripts I write for work to make Spreadsheet City more habitable. But I have multiple CS degrees and a lot of years of experience. I'm not a doctor who decides to implement what his or her office needs.

I suspect there are more people today like Crawshaw's father than I hear about. I wish it were more of a culture that we cultivated for everyone. Not everyone wants to bake their own bread, but people who get the itch ought to feel like the world is theirs to explore.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Personal, Software Development

February 29, 2020 11:19 AM

Programming Healthily

... or at least differently. From Inside Google's Efforts to Engineer Its Food for Healthiness:

So, instead of merely changing the food, Bakker changed the foodscape, ensuring that nearly every option at Google is healthy -- or at least healthyish -- and that the options that weren't stayed out of sight and out of mind.

This is how I've been thinking lately about teaching functional programming to my students, who have experience in procedural Python and object-oriented Java. As with deciding what we eat, how we think about problems and programs is mostly unconscious, a mixture of habit and culture. It is also something intimate and individual, perhaps especially for relative beginners who have only recently begun to know a language well enough to solve problems with some facility. But even for us old hands, the languages and mental tools we use to write programs can become personal. That makes change, and growth, hard.

In my last few offerings of our programming languages course, in which students learn Racket and functional style, I've been trying to change the programming landscape my students see in small ways whenever I can. Here are a few things I've done:

  • I've shrunk the set of primitive functions that we use in the first few weeks. A larger set of tools offers more power and reach, but it also can distract. I'm hoping that students can more quickly master the small set of tools than the larger set and thus begin to feel more accomplished sooner.

  • We work for the first few weeks on problems with less need for the tools we've moved out of sight, such as local variables and counter variables. If a program doesn't really benefit from a local variable, students will be less likely to reach for one. Instead, perhaps, they will reach for a function that can help them get closer to their goal.

  • In a similar vein, I've tried to make explicit connections between specific triggers ("We're processing a list of data, so we'll need a loop.") with new responses ("map can help us here."). We then follow up these connections with immediate and frequent practice.

By keeping functional tools closer at hand, I'm trying to make it easier for these tools to become the new habit. I've also noticed how the way I speak about problems and problem solving can subtly shape how students approach problems, so I'm trying to change a few of my own habits, too.

It's hard for me to do all these things, but it's harder still when I'm not thinking about them. This feels like progress.

So far students seem to be responding well, but it will be a while before I feel confident that these changes in the course are really helping students. I don't want to displace procedural or object-oriented thinking from their minds, but rather to give them a new tool set they can bring out when they need or want to.


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

February 18, 2020 4:00 PM

Programming Feels Like Home

I saw Robin Sloan's An App Can Be a Home-Cooked Meal floating around Twitter a few days back. It really is quite good; give it a read if you haven't already. This passage captures a lot of the essay's spirit in only a few words:

The exhortation "learn to code!" has its foundations in market value. "Learn to code" is suggested as a way up, a way out. "Learn to code" offers economic leverage, a squirt of power. "Learn to code" goes on your resume.
But let's substitute a different phrase: "learn to cook." People don't only learn to cook so they can become chefs. Some do! But far more people learn to cook so they can eat better, or more affordably, or in a specific way. Or because they want to carry on a tradition. Sometimes they learn just because they're bored! Or even because -- get this -- they love spending time with the person who's teaching them.

Sloan expresses better than I ever have an idea that I blog about every so often. Why should people learn to program? Certainly it offers a path to economic gain, and that's why a lot of students study computer science in college, whether as a major, a minor, or a high-leverage class or two. There is nothing wrong with that. It is for many a way up, a way out.

But for some of us, there is more than money in programming. It gives you a certain power over the data and tools you use. I write here occasionally about how a small script or a relatively small program makes my life so much easier, and I feel bad for colleagues who are stuck doing drudge work that I jump past. Occasionally I'll try to share my code, to lighten someone else's burden, but most of the time there is such a mismatch between the worlds we live in that they are happier to keep plugging along. I can't say that I blame them. Still, if only they could program and used tools that enabled them to improve their work environments...

But... There is more still. From the early days of this blog, I've been open with you all:

Here's the thing. I like to write code.

One of the things that students like about my classes is that I love what I do, and they are welcome to join me on the journey. Just today a student in my Programming Languages drifted back to my office with me after class , where we ended up talking for half an hour and sketching code on a whiteboard as we deconstructed a vocabulary choice he made on our latest homework assignment. I could sense this student's own love of programming, and it raised my spirits. It makes me more excited for the rest of the semester.

I've had people come up to me at conferences to say that the reason they read my blog is because they like to see someone enjoying programming as much as they do. many of them share links with their students as if to say, "See, we are not alone." I look forward to days when I will be able to write in this vein more often.

Sloan reminds us that programming can be -- is -- more than a line on a resume. It is something that everyone can do, and want to do, for a lot of different reasons. It would be great if programming "were marbled deeply into domesticity and comfort, nerdiness and curiosity, health and love" in the way that cooking is. That is what makes Computing for All really worth doing.


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

February 10, 2020 2:37 PM

Some Things I Read Recently

Campaign Security is a Wood Chipper for Your Hopes and Dreams

Practical campaign security is a wood chipper for your hopes and dreams. It sits at the intersection of 19 kinds of status quo, each more odious than the last. You have to accept the fact that computers are broken, software is terrible, campaign finance is evil, the political parties are inept, the DCCC exists, politics is full of parasites, tech companies are run by arrogant man-children, and so on.

This piece from last year has some good advice, plenty of sarcastic humor from Maciej, and one remark that was especially timely for the past week:

You will fare especially badly if you have written an app to fix politics. Put the app away and never speak of it again.

Know the Difference Between Neurosis and Process

In a conversation between Tom Waits and Elvis Costello from the late 1980s, Waits talks about tinkering too long with a song:

TOM: "You have to know the difference between neurosis and actual process, 'cause if you're left with it in your hands for too long, you may unravel everything. You may end up with absolutely nothing."

In software, when we keep code in our hands for too long, we usually end up with an over-engineered, over-abstracted boat anchor. Let the tests tell you when you are done, then stop.

Sometimes, Work is Work

People say, "if you love what you do you'll never work a day in your life." I think good work can be painful--I think sometimes it feels exactly like work.

Some weeks more than others. Trust me. That's okay. You can still love what you do.


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

January 22, 2020 3:54 PM

The Roots of TDD -- from 1957

In 1957, Dan McCracken published Digital Computer Programming, perhaps the first book on the new art of programming. His book shows that the roots of extreme programming run deep. In this passage, McCracken encourages both the writing of tests before the writing of code and the involvement of the customer in the software development process:

The first attack on the checkout problem may be made before coding is begun. In order to fully ascertain the accuracy of the answers, it is necessary to have a hand-calculated check case with which to compare the answers which will later be calculated by the machine. This means that stored program machines are never used for a true one-shot problem. There must always be an element of iteration to make it pay. The hand calculations can be done at any point during programming. Frequently, however, computers are operated by computing experts to prepare the problems as a service for engineers or scientists. In these cases it is highly desirable that the "customer" prepare the check case, largely because logical errors and misunderstandings between the programmer and customer may be pointed out by such procedure. If the customer is to prepare the test solution is best for him to start well in advance of actual checkout, since for any sizable problem it will take several days or weeks to calculate the test.

I don't have a copy of this book, but I've read a couple of other early books by McCracken, including one of his Fortran books for engineers and scientists. He was a good writer and teacher.

I had the great fortune to meet Dan at an NSF workshop in Clemson, South Carolina, back in the mid-1990s. We spent many hours in the evening talking shop and watching basketball on TV. (Dan was cheering his New York Knicks on in the NBA finals, and he was happy to learn that I had been a Knicks and Walt Frazier fan in the 1970s.) He was a pioneer of programming and programming education who was willing to share his experience with a young CS prof who was trying to figure out how to teach. We kept in touch by email thereafter. It was honor to call him a friend.

You can find the above quotation in A History of Test-Driven Development (TDD), as Told in Quotes, by Rob Myers. That post includes several good quotes that Myers had to cut from his upcoming book on TDD. "Of course. How else could you program?"


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

January 10, 2020 2:25 PM

Questions

I recently read an interview with documentary filmmaker Errol Morris, who has unorthodox opinions about documentaries and how to make them. In particular, he prefers to build his films out of extended interviews with a single subject. These interviews give him all the source material he needs, because they aren't about questions and answers. They are about stories:

First of all, I think all questions are more or less rhetorical questions. No one wants their questions answered. They just want to state their question. And, in answering the question, the person never wants to answer the question. They just want to talk.

Morris isn't asking questions; he is stating them. His subjects are not answering questions; they are simply talking.

(Think about this the next time your listening to an interview with a politician or candidate for office...)

At first, I was attracted to the sentiment in this paragraph. Then I became disillusioned with what I took to be its cynicism. Now, though, after a week or so, I am again enamored with its insight. How many of the questions I ask of software clients and professional colleagues are really statements of a position? How many of their answers are disconnected from the essential element of my questions? Even when these responses are disconnected, they communicate a lot to me, if only I listen. My clients and colleagues are often telling me exactly what they want me to know. This dynamic is present surprisingly often when I work with students at the university, too. I need to listen carefully when students don't seem to be answering my question. Sometimes it's because they have misinterpreted the question, and I need to ask differently. Sometimes it's because they are telling me what they want me to know, irrespective of the question.

And when my questions aren't really questions, but statements or some other speech act... well, I know I have some work to do.

In case you find Morris's view on interviews cynical and would prefer to ponder the new year with greater hope, I'll leave you with a more ambiguous quote about questions:

There are years that ask questions, and years that answer.

That's from Their Eyes Were Watching God, by Zora Neale Hurston. In hindsight, it may be true or false for any given year. As a way to frame the coming months, though, it may be useful.

I hope that 2020 brings you the answers you seek, or the questions.


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

December 20, 2019 1:45 PM

More Adventures in Constrained Programming: Elo Predictions

I like tennis. The Tennis Abstract blog helps me keep up with the game and indulge my love of sports stats at the same time. An entry earlier this month gave a gentle introduction to Elo ratings as they are used for professional tennis:

One of the main purposes of any rating system is to predict the outcome of matches--something that Elo does better than most others, including the ATP and WTA rankings. The only input necessary to make a prediction is the difference between two players' ratings, which you can then plug into the following formula:

1 - (1 / (1 + (10 ^ (difference / 400))))

This formula always makes me smile. The first computer program I ever wrote because I really wanted to was a program to compute Elo ratings for my high school chess club. Over the years I've come back to Elo ratings occasionally whenever I had an itch to dabble in a new language or even an old favorite. It's like a personal kata of variable scope.

I read the Tennis Abstract piece this week as my students were finishing up their compilers for the semester and as I was beginning to think of break. Playful me wondered how I might implement the prediction formula in my students' source language. It is a simple functional language with only two data types, integers and booleans; it has no loops, no local variables, no assignments statements, and no sequences. In another old post, I referred to this sort of language as akin to an integer assembly language. And, heaven help me, I love to program in integer assembly language.

To compute even this simple formula in Klein, I need to think in terms of fractions. The only division operator performs integer division, so 1/x for any x gives 0. I also need to think carefully about how to implement the exponentiation 10 ^ (difference / 400). The difference between two players' ratings is usually less than 400 and, in any case, almost never divisible by 400. So My program will have to take an arbitrary root of 10.

Which root? Well, I can use our gcd() function (implemented using Euclid's algorithm, of course) to reduce diff/400 to its lowest terms, n/d, and then compute the dth root of 10^n. Now, how to take the dth root of an integer for an arbitrary integer d?

Fortunately, my students and I have written code like this in various integer assembly languages over the years. For instance, we have a SQRT function that uses binary search to hone in on the integer closest to the square of a given integer. Even better, one semester a student implemented a square root program that uses Newton's method:

   xn+1 = xn - f(xn)/f'(xn)

That's just what I need! I can create a more general version of the function that uses Newton's method to compute an arbitrary root of an arbitrary base. Rather than work with floating-point numbers, I will implement the function to take its guess as a fraction, represented as two integers: a numerator and a denominator.

This may seem like a lot of work, but that's what working in such a simple programming language is like. If I want my students' compilers to produce assembly language that predicts the result of a professional tennis match, I have to do the work.

This morning, I read a review of Francis Su's new popular math book, Mathematics for Human Flourishing. It reminds us that math isn't about rules and formulas:

Real math is a quest driven by curiosity and wonder. It requires creativity, aesthetic sensibilities, a penchant for mystery, and courage in the face of the unknown.

Writing my Elo rating program in Klein doesn't involve much mystery, and it requires no courage at all. It does, however, require some creativity to program under the severe constraints of a very simple language. And it's very much true that my little programming diversion is driven by curiosity and wonder. It's fun to explore ideas in a small space uses limited tools. What will I find along the way? I'll surely make design choices that reflect my personal aesthetic sensibilities as well as the pragmatic sensibilities of a virtual machine that know only integers and booleans.

As I've said before, I love to program.


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

December 12, 2019 3:20 PM

A Semester's Worth of Technical Debt

I've been thinking a lot about technical debt this week. My student teams are in Week 13 of their compiler project and getting ready to submit their final systems. They've been living with their code long enough now to appreciate Ward Cunningham's original idea of technical debt: the distance between their understanding and the understanding embodied in their systems.

... it was important to me that we accumulate the learnings we did about the application over time by modifying the program to look as if we had known what we were doing all along and to look as if it had been easy to do in Smalltalk.

Actually, I think they are experiencing two gulfs: one relates to their understanding of the domain, compilers, and the other to their understanding of how to build software. Obviously, they are just learning about compilers and how to build one, so their content knowledge has grown rapidly while they've been programming. But they are also novice software engineers. They are really just learning how to build a big software system of any kind. Their knowledge of project management, communication, and their tools has also grown rapidly in parallel with building their system.

They have learned a lot about both content and process this semester. Several of them wish they had time to refactor -- to pay back the debt they accumulated honestly along the way -- but university courses have to end. Perhaps one or two of them will do what one or two students in most past semesters have done: put some of their own time into their compilers after the course ends, to see if they can modify the program to look as if they had known what they were doing all along, and to look as if it had been easy to do in Java or Python. There's a lot of satisfaction to be found at the end of that path, if they have the time and curiosity to take it.

One team leader tried to bridge the gulf in real time over the last couple of weeks: He was so unhappy with the gap between his team's code and their understanding that he did a complete rewrite of the first five stages of their compiler. This team learned what every team learns about rewrites and large-scale refactoring: they spend time that could otherwise have been spent on new development. In a time-boxed course, this doesn't always work well. That said, though, they will likely end up with a solid compiler -- as well as a lot of new knowledge about how to build software.

Being a prof is fun in many ways. One is getting to watch students learn how to build something while they are building it, and coming out on the other side with new code and new understanding.


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

December 06, 2019 2:42 PM

OOP As If You Meant It

This morning I read an old blog post by Michael Feathers, The Flawed Theory Behind Unit Testing. It discusses what makes TDD and Clean Room software development so effective for writing code with fewer defects: they define practices that encourage developers to work in a continuous state of reflection about their code. The post holds up well ten years on.

The line that lit my mind up, though, was this one:

John Nolan gave his developers a challenge: write OO code with no getters.

Twenty-plus years after the movement of object-oriented programming into the mainstream, this still looks like a radical challenge to many people. "Whenever possible, tell another object to do something rather than ask for its data." This sort of behavioral abstraction is the heart of OOP and the source of its design power. Yet it is rare to find big Java or C++ systems where most classes don't provide public accessors. When you open that door, client code will walk in -- even if you are the person writing the client code.

Whenever I look at a textbook intended for teaching undergraduates OOP, I look to see how it introduces encapsulation and the use of "getters" and "setters". I'm usually disappointed. Most CS faculty think doing otherwise would be too extreme for relative beginners. Once we open the door , though, it's a short step to using (gulp) instanceof to switch on kinds of objects. No wonder that some students are unimpressed and that too many students don't see any much value in OO programming, which as they learn it doesn't feel much different from what they've done before but which puts new limitations on them.

To be honest, though, it is hard to go Full Metal OOP. Nolan was working with professional programmers, not second-year students, and even so programming without getters was considered a challenge for them. There are certainly circumstances in which the forces at play may drive us toward cracking the door a bit and letting an instance variable sneak out. Experienced programmers know how to decide when the trade-off is worth it. But our understanding the downside of the trade-off is improved after we know how to design independent objects that collaborate to solve problems without knowing anything about the other objects beyond the services they provide.

Maybe we need to borrow an idea from the TDD As If You Meant It crowd and create workshops and books that teach and practice OOP as if we really meant it. Nolan's challenge above would be one of the central tenets of this approach, along with the Polymorphism Challenge and other practices that look odd to many programmers but which are, in the end, the heart of OOP and the source of its design power.

~~~~~

If you like this post, you might enjoy The Summer Smalltalk Taught Me OOP. It's isn't about OOP itself so much as about me throwing away systems until I got it right. But the reason I was throwing systems away was that I was still figuring out how to build an object-oriented system after years programming procedurally, and the reason I was learning so much was that I was learning OOP by building inside of Smalltalk and reading its standard code base. I'm guessing that code base still has a lot to teach many of us.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

December 04, 2019 2:42 PM

Make Your Code Say What You Say When You Describe It

Brian Marick recently retweeted this old tweet from Ron Jeffries:

You: Explain this code to me, please.
They: blah blah blah.
You: Show me where the code says that.
They: <silence>
You: Let's make it say that.

I find this strategy quite helpful when writing my own code. If I can't explain any bit of code to myself clearly and succinctly, then I can take a step back and work on fixing my understanding before trying to fix the code. Once I understand, I'm a big fan of creating functions or methods whose names convey their meaning.

This is also a really handy strategy for me in my teaching. As a prof, I spend a fair amount of time explaining code I've written to students. The act of explaining a piece of code, whether written or spoken, often points me toward ways I can make the program better. If I find myself explaining the same piece of code to several students over time, I know the code can probably be better. So I try to fix it.

I also use a gentler variation of Jeffries' approach when working directly with students and their code. I try whenever I can to help my students learn how to write better programs. It can be tempting to start lecturing them on ways that their program could be better, but unsolicited advice of this sort rarely finds a happy place to land in their memory. Asking questions can be more effective, because questions can lead to a conversation in which students figure some things out on their own. Asking general questions usually isn't helpful, though, because students may not have enough experience to connect the general idea to the details of their program.

So: I find it helpful to ask a student to explain their code to me. Often they'll give me a beautiful answer, short and clear, that stands in obvious contrast to the code we are looking at out. This discrepancy leads to a natural follow-up question: How might we change the code so that it says that? The student can take the lead in improving their own programs, guided by me with bits of experience they haven't had yet.

Of course, sometimes the student's answer is complex or rambles off into silence. That's a cue to both of us that they don't really understand yet what they are trying to do. We can take a step back and help them fix their understanding -- of the problem or of the programming technique -- before trying to fix the code itself.


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

December 02, 2019 11:41 AM

XP as a Long-Term Learning Strategy

I recently read Anne-Laure Le Cunff's Interleaving: Rethink The Way You Learn. Le Cunff explains why interleaving -- "the process of mixing the practice of several related skills together" -- is more effective for long-term learning than blocked practice, in which students practice a single skill until they learn it and then move on to the next skill. Interleaving forces the brain to retrieve different problem-solving strategies more frequently and under different circumstances, which reinforces neural connections and improves learning.

To illustrate the distinction between interleaving and blocked practice, Le Cunff uses this image:

interleaving versus blocked practice

When I saw that diagram, I thought immediately of Extreme Programming. In particular, I thought of a diagram I once saw that distinguished XP from more traditional ways of building software in terms of how quickly it moved through the steps of the development life cycle. That image looked something like this:

XP interleaves the stages of the software development life cycle

If design is good, why not do it all the time? If testing is good, why not do it all the time, too?

I don't think that the similarity between these two images is an accident. It reflects one of XP's most important, if sometimes underappreciated, benefits: By interleaving short spurts of analysis, design, implementation, and testing, programmers strengthen their understanding of both the problem and the evolving code base. They develop stronger long-term memory associations with all phases of the project. Improved learning enables them to perform even more effectively deeper in the project, when these associations are more firmly in place.

Le Cunff offers a caveat to interleaved learning that also applies to XP: "Because the way it works benefits mostly our long-term retention, interleaving doesn't have the best immediate results." The benefits of XP, including more effective learning, accrue to teams that persist. Teams new to XP are sometimes frustrated by the small steps and seemingly narrow focus of their decisions. With a bit more experience, they become comfortable with the rhythm of development and see that their code base is more supple. They also begin to benefit from the more effective learning that interleaved practice provides.

~~~~

Image 1: This image comes from Le Cunff's article, linked above. It is by Anne-Laure Le Cunff, copyright Ness Labs 2019, and reproduced here with permission.

Image 2: I don't remember where I saw the image I hold in my memory, and a quick search through Extreme Programming Explained and Google's archives did not turn up anything like it. So I made my own. It is licensed CC BY-SA 4.0.


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

October 25, 2019 3:55 PM

Enjoyment Bias in Programming

Earlier this week, I read this snippet about the benefits of "enjoyment bias" in Morgan Housel's latest blog post:

2. Enjoyment bias: An inefficient investing strategy that you enjoy will outperform an efficient one that feels like work because anything that feels like work will eventually be abandoned.
Getting anything to work requires giving it an appropriate amount of time. Giving it time requires not getting bored or burning out. Not getting bored or burning out requires that you love what you're doing, because that's when the hard parts become acceptable.

The programmer in me immediately thought, "I have this pattern." My guess is that this bias applies to a lot of things outside of investing. In software development, the choices of development methodology and programming language often benefit from enjoyment bias.

In programming as in investing, we can take this too far and hurt ourselves, our teams, and our users. Anything can be overdone. But, in general, we are more likely to stick with the hard work of building software when we enjoy the way we are building it and the tools we are using. Don't let others shame you away from what works for you.

This bias actually reminded me of a short bit from one of Paul Graham's essays on, of all things, procrastination:

I think the way to "solve" the problem of procrastination is to let delight pull you instead of making a to-do list push you. Work on an ambitious project you really enjoy, and sail as close to the wind as you can, and you'll leave the right things undone.

Delight can keep you happily working when the going gets rough, and it can pull you toward work when a lack of delight would leave you killing time on stuff that doesn't matter.

(By the way, I think that several other biases described by Housel are also useful in programming. Consider the value of reasonable ignorance, number three on his list....)


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

September 13, 2019 3:12 PM

How a government boondoggle paved the way for the expansion of computing

In an old interview at Alphachatterbox, economist Brad DeLong adds another programming tale to the annals of unintended consequences:

So the Sage Air Defense system, which never produced a single usable line of software running on any piece of hardware -- we spent more on the Sage Air Defense System than we did on the entire Manhattan Project. And it was in one sense the ultimate government Defense Department boondoggle. But on the other hand it trained a whole generation of computer programmers at a time when very little else was useful that computer programmers could exercise their skills on.
And by the time the 1960s rolled around we not only ... the fact that Sage had almost worked provided say American Airlines with the idea that maybe they should do a computer-driven reservations system for their air travel, which I think was the next big Manhattan Project-scale computer programming project.
And as that moved on the computer programmers began finding more and more things to do, especially after IBM developed its System 360.
And we were off and running.

As DeLong says earlier in the conversation, this development upended IBM president Thomas Watson's alleged claim that there was "a use for maybe five computers in the world". This famous quote is almost certainly an urban legend, but Watson would not have been as off-base as people claim even if he had said it. In the 1950s, there was not yet a widespread need for what computers did, precisely because most people did not yet understand how computing could change the landscape of every activity. Training a slew of programmers for a project that ultimately failed had the unexpected consequence of creating the intellectual and creative capital necessary to begin exploring the ubiquitous applications of computing. Money unexpectedly well spent.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

September 12, 2019 3:57 PM

Pain and Shame

Today's lecture notes for my course include a link to @KentBeck's article on Prune, which I still enjoy.

The line that merits its link in today's session is:

We wrote an ugly, fragile state machine for our typeahead, which quickly became a source of pain and shame.

My students will soon likely experience those emotions about the state machines; they are building for lexers for their semester-long compiler project. I reassure them: These emotions are normal for programmers.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

June 28, 2019 3:39 PM

Another Peter Principle-Like Observation

Raganwald tweeted:

If you design a language for people who have a talent for managing accidental complexity, you'll beget more and more accidental complexity over time.
Someone who can manage accidental complexity will always take on more if it makes them more productive.

This reminded me of a blog post from last November in which I half-jokingly coined The Peter Principle of Software Growth:

Software grows until it exceeds our capacity to understand it.

In the case of Raganwald's tweet, languages that enable us to handle accidental complexity well lead to more accidental complexity, because the people who use them will be more be more ambitious -- until they reach their saturation point. Both of these observations about software resemble the original Peter Principle, in which people who succeed are promoted until they reach a point at which they can't, or don't, succeed.

I am happy to dub Raganwald's observation "The Peter Principle of Accidental Complexity", but after three examples, I begin to recognize a pattern... Is there a general name for this phenomenon, in which successful actors advance or evolve naturally until they reach a point at which the can't, or don't, succeed?

If you have any ideas, please email me or respond on Twitter.

In a playful mood at the end of a strange and hectic week, I am now wondering whether there is a Peter Principle of Peter Principles.


Posted by Eugene Wallingford | Permalink | Categories: General, Software Development

June 20, 2019 3:51 PM

Implementing a "Read Lines" Operator in Joy

I wasn't getting any work done today on my to-do list, so I decided to write some code.

One of my learning exercises to open the Summer of Joy is to solve the term frequency problem from Crista Lopes's Exercises in Programming Style. Joy is a little like Scheme: it has a lot of cool operations, especially higher-order operators, but it doesn't have much in the way of practical level tools for basic tasks like I/O. To compute term frequencies on an arbitrary file, I need to read the file onto Joy's stack.

I played around with Joy's low-level I/O operators for a while and built a new operator called readfile, which expects the pathname for an input file on top of the stack:

    DEFINE readfile ==
        (* 1 *)  [] swap "r" fopen
        (* 2 *)  [feof not] [fgets swap swonsd] while
        (* 3 *)  fclose.

The first line leaves an empty list and an input stream object on the stack. Line 2 reads lines from the file and conses them onto the list until it reaches EOF, leaving a list of lines under the input stream object on the stack. The last line closes the stream and pops it from the stack.

This may not seem like a big deal, but I was beaming when I got it working. First of all, this is my first while in Joy, which requires two quoted programs. Second, and more meaningful to me, the loop body not only works in terms of the dip idiom I mentioned in my previous post, it even uses the higher-order swonsd operator to implement the idiom. This must be how I felt the first time I mapped an anonymous lambda over a list in Scheme.

readfile leaves a list of lines on the stack. Unfortunately, the list is in reverse order: the last line of the file is the front of the list. Besides, given that Joy is a stack-based language, I think I'd like to have the lines on the stack itself. So I noodled around some more and implemented the operator pushlist:

    DEFINE pushlist ==
        (* 1 *)  [ null not ] [ uncons ] while
        (* 2 *)  pop.

Look at me... I get one loop working, so I write another. The loop on Line 1 iterates over a list, repeatedly taking (head . tail) and pushing head and tail onto the stack in that order. Line 2 pops the empty list after the loop terminates. The result is a stack with the lines from the file in order, first line on top:

    line-n ... line-3 line-2 line-1

Put readfile and pushlist together:

    DEFINE fileToStack == readfile pushlist.
and you get fileToStack, something like Python's readlines() function, but in the spirit of Joy: the file's lines are on the stack ready to be processed.

I'll admit that I'm pleased with myself, but I suspect that this code can be improved. Joy has a lot of dandy higher-order operators. There is probably a better way to implement pushlist and maybe even readfile. I won't be surprised if there is a more idiomatic way to implement the two that makes the two operations plug together with less rework. And I may find that I don't want to leave bare lines of text on the stack after all and would prefer having a list of lines. Learning whether I can improve the code, and how, are tasks for another day.

My next job for solving the term frequency problem is to split the lines into individual words, canonicalize them, and filter out stop words. Right now, all I know is that I have two more functions in my toolbox, I learned a little Joy, and writing some code made my day better.


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

June 11, 2019 3:04 PM

Summer of Joy

"Elementary" ideas are really hard & need to be revisited
& explored & re-revisited at all levels of mathematical
sophistication. Doing so actually moves math forward.

-- James Tanton

Three summers ago, I spent a couple of weeks re-familiarizing myself with the concatenative programming language Joy and trying to go a little deeper with the style. I even wrote a few blog entries, including a few quick lessons I learned in my first week with the language. Several of those lessons hold up, but please don't look at the code linked there; it is the raw code of a beginner who doesn't yet get the idioms of the style or the language. Then other duties at work and home pulled me away, and I never made the time to get back to my studies.

my Summer of Joy folder

I have dubbed this the Summer of Joy. I can't devote the entire summer to concatenative programming, but I'm making a conscious effort to spend a couple of days each week in real study and practice. After only one week, I have created enough forward momentum that I think about problems and solutions at random times of the day, such as while walking home or making dinner. I think that's a good sign.

An even better sign is that I'm starting to grok some of the idioms of the style. Joy is different from other concatenative languages like Forth and Factor, but it shares the mindset of using stack operators effectively to shape the data a program uses. I'm finally starting to think in terms of dip, an operator that enables a program to manipulate data just below the top of the stack. As a result, a lot of my code is getting smaller and beginning to look like idiomatic Joy. When I really master dip and begin to think in terms of other "dipping" operators, I'll know I'm really on my way.

One of my goals for the summer is to write a Joy compiler from scratch that I can use as a demonstration in my fall compiler course. Right now, though, I'm still in Joy user mode and am getting the itch for a different sort of language tool... As my Joy skills get better, I find myself refactoring short programs I've written in the past. How can I be sure that I'm not breaking the code? I need unit tests!

So my first bit of tool building is to implement a simple JoyUnit. As a tentative step in this direction, I created the simplest version of RackUnit's check-equal? function possible:

    DEFINE check-equal == [i] dip i =.
This operator takes two quoted programs (a test expression and an expected result), executes them, and compares the results. For example, this test exercises a square function:
    [ 2 square ] [ 4 ] check-equal.

This is, of course, only the beginning. Next I'll add a message to display when a test fails, so that I can tell at a glance which tests have failed. Eventually I'll want my JoyUnit to support tests as objects that can be organized into suites, so that their results can be tallied, inspected, and reported on. But for now, YAGNI. With even a few simple functions like this one, I am able to run tests and keep my code clean. That's a good feeling.

To top it all off, implementing JoyUnit will force me to practice writing Joy and push me to extend my understanding while growing the set of programming tools I have at my disposal. That's another good feeling, and one that might help me keep my momentum as a busy summer moves on.


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

May 22, 2019 1:45 PM

The Futility of Software

A thought from <antirez> in an essay on the struggles of an open source maintainer (paraphrased a bit):

Sometimes I believe that writing software, while great, will never be huge like writing a book that will survive for centuries. Not because software is not as great per se, but because as a side effect it is also useful... and will be replaced when something more useful is around.

We write most software with a particular use in mind, so it is really only fair to compare it to non-fiction books, which also have a relatively short shelf life. To be fair, though, not many fiction books survive for centuries, either. Language and fashion doom them almost as much as evolving technology destines most software to fade away within a generation, and a short generation at that.

Still, I won't be surprised if the DNA of Smalltalk-80 or some early Lisp implementation lives on deep in a system that developers use in the 22nd century.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

May 07, 2019 11:15 AM

A PL Design Challenge from Alan Kay

In an answer on Quora from earlier this year:

There are several modern APL-like languages today -- such as J and K -- but I would criticize them as being too much like the classic APL. It is possible to extract what is really great from APL and use it in new language designs without being so tied to the past. This would be a great project for some grad students of today: what does the APL perspective mean today, and what kind of great programming language could be inspired by it?

The APL perspective was more radical even twenty years ago, before MapReduce became a thing and before functional programming ascended. When I was an undergrad, though, it seemed otherworldly: setting up a structure, passing it through a sequence of operators that changed its shape, and then passing it through a sequence of operators that folded up a result. We knew we weren't programming in Fortran anymore.

I'm still fascinated by APL, but I haven't done a lot with it in the intervening years. These days I'm still thinking about concatenative programming in languages like Forth, Factor, and Joy, a project I reinitiated (and last blogged about) three summers ago. Most concatenative languages work with an implicit stack, which gives it a very different feel from APL's dataflow style. I can imagine, though, that working in the concision and abstraction of concatenative languages for a while will spark my interest in diving back into APL-style programming some day.

Kay's full answer is worth a read if only for the story in which he connects Iverson's APL notation, and its effect on how we understand computer systems, to the evolution of Maxwell's equations. Over the years, I've heard Kay talk about McCarthy's Lisp interpreter as akin to Maxwell's equations, too. In some ways, the analogy works even better with APL, though it seems that the lessons of Lisp have had a larger historical effect to date.

Perhaps that will change? Alas, as Kay says in the paragraph that precedes his challenge:

As always, time has moved on. Programming language ideas move much slower, and programmers move almost not at all.

Kay often comes off as pessimistic, but after all the computing history he has lived through (and created!), he has earned whatever pessimism he feels. As usual, reading one of his essays makes me want to buckle down and do something that would make him proud.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

April 29, 2019 2:42 PM

The Path to Nothing

Dick Gabriel writes, in Lessons From The Science of Nothing At All:

Nevertheless, the spreadsheet was something never seen before. A chart indicating the 64 greatest events in accounting and business history contains VisiCalc.

This reminds me of a line from The Tao of Pooh:

Take the path to Nothing, and go Nowhere until you reach it.

A lot of research is like this, but even more so in computer science, where the things we produce are generally made out of nothing. Often, like VisiCalc, they aren't really like anything we've ever seen or used before either.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

April 08, 2019 11:55 AM

TDD is a Means for Delaying Intuition

In one of his "Conversations with Tyler", Tyler Cowen talks with Daniel Kahneman about intuition and its relationship to thinking fast and slow. According to Kahneman, evidence supports his position that most people have not had the experience necessary to develop intuition that is good enough for solving problems directly. So he thinks that most people, including most so-called experts, should slow down.

So I think delaying intuition is a very good idea. Delaying intuition until the facts are in, at hand, and looking at dimensions of the problem separately and independently is a better use of information.

The problem with intuition is that it forms very quickly, so that you need to have special procedures in place to control it except in those rare cases...

...

Break the decision up. It's not so much a matter of time because you don't want people to get paralyzed by analysis. But it's a matter of planning how you're going to make the decision, and making it in stages, and not acting without an intuitive certainty that you are doing the right thing. But just delay it until all the information is available.

This is one of the things that I find most helpful about test-driven design when I practice it faithfully. It's pretty easy for me to think that I know everything I need to implement a program after I've read the spec and thought about it for a few minutes. I mean, I've written a lot of code over the years... If my intuition tells me where to go, I can start right away and have the whole path ahead of me in my mind.

But how often do I really have evidence that my intuitive plan is the correct one? If I'm wrong, I'll spend a bunch of time and write a bunch of code, only later to find out I'm wrong. What's worse, all that code I've written usually ends up feeling like a constraint within which I have to work as I try to dig myself out of the mess.

Writing one test at a time and implementing just the code I need to pass it is a way to force my intuitive mind to slow down. It helps me think about the actual problem I'm solving, rather than the abstraction my expert brain infers from the spec. The program grows slowly along side my understanding and points me in the direction of the next small step to take.

TDD is a procedure I can put in place to help me control my intuition until the facts are in, and it encourages me to look at different dimensions of the problem independently as write the code to solve them.


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

April 04, 2019 4:40 PM

A Non-Software Example of Preparatory Refactoring

When I refactor my code, I most often think in terms of what Martin Fowler calls preparatory refactoring: if it's difficult to add a new feature to my program, I refactor the existing code into a state where the feature fits naturally somewhere, then I add the feature. As is often the case, Kent Beck captured this notion memorably in a tweet-sized aphorism. I was delighted to see that Martin's blog post, which I remember fondly, cites the same tweet!

Ideas from programming are usually instances of more general ideas from the broader world, specialized to a world of bits and computation. Back when I taught our object-oriented programming course every semester, I often referred my students to a web site that offered real-life examples of the various design patterns we were learning. I remember an example of Decorator that showed how we can embellish a painting with a matte or a frame, and its use of the U.S. Constitution's specification of the President to illustrate the idea of a Singleton. I can't find that site on the web just now, but there's almost surely a local copy buried in one of my course websites from way back.

The idea of refactoring is useful outside the world of software, too. Just yesterday, my dean suggested what I consider to be a preparatory refactoring.

A committee on campus is charged with proposing ways that the university can restructure its colleges and departments. With the exception of a merger of two colleges a few years ago, we have had essentially the same academic structure for my entire time here. In those years, disciplines have changed and budgets have changed, so now the administration is thinking that the university might be more efficient or more productive with a different structure. Thinking about the process from this perspective, restructuring is largely a reaction to change that has already happened.

My dean suggested another way to approach the task. Think, he said, of the new academic programs that you'd like to create in the future. We may not have money available right now to create a new major or to organize a new research center, but one day we might. What university structure would make adding this program go more smoothly and work better once in place? Which departments would the new program want to work with? Which administrative structures already in place would minimize unnecessary overhead of the new program? As much as possible, he suggested, let's try to create a new academic structure that suits the future programs we'd like to build. That will reduce friction later, which is good: Administrative friction often grinds new academic ideas to a halt before they get off the ground.

In programming terms, this is quite bit different than the sort of refactoring I prefer. I try to practice YAGNI and refactor only for the specific feature that I want to add right now, not taking into account imagined future features I may never need. In terms of academic structure, though, this sort of ip-front design makes a lot of sense. Academic structures are much harder to change than software; getting a few things right now may make future changes at the program level much easier to implement later.

Thinking about academic restructuring this way has another positive side effect: it might entice faculty to be more engaged, because what we do now matters to the future we would like to build. It's not merely a reaction to past changes.

My dean is suggesting that we build academic structures now that make the changes we want to implement later (when the resources and requisite will exist) easier to implement. Building those structures now may take more work than simply responding to past changes, but it will be worth the effort when we are ready to create new programs. I think Kent and Martin might be proud.


Posted by Eugene Wallingford | Permalink | Categories: Managing and Leading, Patterns, Software Development

March 17, 2019 10:59 AM

Are We Curious Enough About Our Students?

I ran across an old interview with Douglas Crockford recently. When asked what traits were common to the weak programmers he'd seen over his career, Crockford said:

That's an easy one: lack of curiosity. They were so satisfied with the work that they were doing was good enough (without an understanding of what 'good' was) that they didn't push themselves.

I notice a lack of curiosity in many CS students, too. It's even easier for beginners than professional programmers to be satisfied with meeting the minimal requirements of a project -- "I got the right answers!" or, much worse, "It compiles!" -- and not realize that good code can be more. Part of our goal as teachers is to help students develop higher standards and more refined taste while they are in school.

There's another sense, though, in which holding students' lack of curiosity against them is a dangerous trap for professors. In moments of weakness, I occasionally look at my students and think, "Why doesn't this excite them more? Why don't they want to write code for fun?" I've come to realize over the years that our school system doesn't always do much to help students cultivate their curiosity. But with a little patience and a little conversation, I often find that my students are curious -- just not always about the things that intrigue me.

This shouldn't be a surprise. Even at the beginning of my career as a prof, I was a different sort of person than most of my students. Now that I'm a few years older, it's almost certain that I will not be in close connection with my students and what interests them most. Why would they necessarily care about the things I care about?

Bridging this gap takes time and energy. I have to work to build relationships both with individuals and with the group of students taking my course each semester. This work requires patience, which I've learned to appreciate more and more as I've taught. We don't always have the time we need in one semester, but that's okay. One of the advantages of teaching at a smaller school is time: I can get to know students over several semesters and multiple courses. We have a chance to build relationships that enrich the students' learning experience -- and my experience as a teacher.

Trying to connect with the curiosity of many different students creates logistical challenges when designing courses, examples, and assignments, of course. I'm often drawn back to Alan Kay's paradigm, Frank Oppenheimer's Exploratorium, which Kay discussed in his Turing Award lecture. The internet is, in many ways, a programmer's exploratorium, but it's so big, so disorganized, and of such varying levels of quality... Can we create collections of demos and problems that will contain something to connect with just about every student? Many of my posts on this blog, especially in the early years, grappled with this idea. (Here are two that specifically mention the Exploratorium: Problems Are The Thing and Mathematics, Problems, and Teaching.)

Sometimes I think the real question isn't: "Why aren't students more curious?" It is: "Are we instructors curious enough about our students?"


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

March 10, 2019 10:53 AM

Weekend Shorts

Andy Ko, in SIGCSE 2019 report:

I always have to warn my students before they attend SIGCSE that it's not a place for deep and nuanced discussions about learning, nor is it a place to get critical feedback about their ideas.
It is, however, a wonderful place to be immersed in the concerns of CS teachers and their perceptions of evidence.

I'm not sure I agree that one can't have deep, nuanced discussions about learning at SIGCSE, but it certainly is not a research conference. It is a great place to talk to and learn from people in the trenches teaching CS courses, with a strong emphasis on the early courses. I have picked up a lot of effective, creative, and inspiring ideas at SIGCSE over the years. Putting them onto sure scientific footing is part of my job when I get back.

~~~~~

Stephen Kell, in Some Were Meant for C (PDF), an Onward! 2017 essay:

Unless we can understand the real reasons why programmers continue to use C, we risk researchers continuing to solve a set of problems that is incomplete and/or irrelevant, while practitioners continue to use flawed tools.

For example,

... "faster safe languages" is seen as the Important Research Problem, not better integration.

... whereas Kell believes that C's superiority in the realm of integration is one of the main reasons that C remains a dominant, essential systems language.

Even with the freedom granted by tenure, academic culture tends to restrict what research gets done. One cause is a desire to publish in the best venues, which encourages work that is valued by certain communities. Another reason is that academic research tends to attract people who are interested in a certain kind of clean problem. CS isn't exactly "round, spherical chickens in a vacuum" territory, but... Language support for system integration, interop, and migration can seem like a grungier sort of work than most researchers envisioned when they went to grad school.

"Some Were Meant for C" is an elegant paper, just the sort of work, I imagine, that Richard Gabriel had when envisioned the essays track at Onward. Well worth a read.


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

February 24, 2019 9:35 AM

Normative

In a conversation with Tyler Cowen, economist John Nye expresses disappointment with the nature of discourse in his discipline:

The thing I'm really frustrated by is that it doesn't matter whether people are writing from a socialist or a libertarian perspective. Too much of the discussion of political economy is normative. It's about "what should the ideal state be?"
I'm much more concerned with the questions of "what good states are possible?" And once good states are created that are possible, what good states are sustainable? And that, in my view, is a still understudied and very poorly understood issue.

For some reason, this made me think about software development. Programming styles, static and dynamic typing, software development methodologies, ... So much that is written about these topics tells us what's the right the thing to do. "Do this, and you will be able to reliably make good software."

I know I've been partisan on some of these issues over the course of my time as a programmer, and I still have my personal preferences. But these days especially I find myself more interested in "what good states are sustainable?". What has worked for teams? What conditions seem to make those practices work well or not so well? How do teams adapt to changes in the domain or the business or the team's make-up?

This isn't too say that we can't draw conclusions about forces and context. For example, small teams seem to make it easier to adapt to changing conditions; to make it work with bigger teams, we need to design systems that encourage attention and feedback. But it does mean that we can help others succeed without always telling them what they must do. We can help them find a groove that syncs with them and the conditions under which they work.

Standing back and surveying the big picture, it seems that a lot of good states are sustainable, so long as we pay attention and adapt to the world around us. And that should be good news to us all.


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

January 29, 2019 1:46 PM

Dependencies and Customizable Books

Shriram Krishnamurthi, in Books as Software:

I have said that a book is a collection of components. I have concrete evidence that some of my users specifically excerpt sections that suit their purpose. ...

I forecast that one day, rich document formats like PDF will recognize this reality and permit precisely such specifications. Then, when a user selects a group of desired chapters to generate a thinner volume, the software will automatically evaluate constraints and include all dependencies. To enable this we will even need "program" analyses that help us find all the dependencies, using textual concordances as a starting point and the index as an auxiliary data structure.

I am one of the users Krishnamurthi speaks of, who has excerpted sections from his Programming Languages: Application and Interpretation to suit the purposes of my course. Though I've not written a book, I do post, use, adapt, and reuse detailed lecture notes for my courses, and as a result I have seen both sides of the divide he discusses. I occasionally change the order of topics in a course, or add a unit, or drop a unit. An unseen bit of work is to account for the dependencies among concepts, examples, problems, and code in the affected sections, but also in the new whole. My life is simpler than book writers who have to deal at least in part with rich document formats: I do everything in a small, old-style subset of HTML, which means I can use simple text-based tools for manipulating everything. But dependencies? Yeesh.

Maybe I need to write a big makefile for my course notes. Alas, that would not help me manage dependencies in the way I'd like, or in the way Krishnamurthi forecasts. As such, it would probably make things worse. I suppose that I could create the tool I need.


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

January 08, 2019 2:10 PM

Sometimes, Copy and Paste Is the Right Thing To Do

Last week I blogged about writing code that is easy to delete, drawing on some great lines from an old 'programming is terrible' post. Here's another passage from @tef's post that's worth thinking more about:

Step 1: Copy-paste code

Building reusable code is something that's easier to do in hindsight with a couple of examples of use in the code base, than foresight of ones you might want later. On the plus side, you're probably re-using a lot of code already just by using the file-system, why worry that much? A little redundancy is healthy.

It's good to copy-paste code a couple of times, rather than making a library function, just to get a handle on how it will be used. Once you make something a shared API, you make it harder to change.

There's not a great one-liner in there, but these paragraphs point to a really important lesson, one that we programmers sometimes have a hard time learning. We are told so often "don't repeat yourself" that we come to think that all repetition is the same. It's not.

One use of repetition is in avoiding what @tef calls, in another 'programming is terrible' post, "preemptive guessing". Consider the creation of a new framework. Oftentimes, designing a framework upfront doesn't work very well because we don't know the domain's abstractions yet. One of the best ways to figure out what they are is to write several applications first, and let framework fall out the applications. While doing this, repetition is our friend: it's most useful to know what things don't change from one application to another. This repetition is a hint on how to build the framework we need. I learned this technique from Ralph Johnson.

I use and teach a similar technique for programming in smaller settings, too. When we see two bits of code that resemble one another, it often helps to increase the duplication in order to eliminate it. (I learned this idea from Kent Beck.) In this case, the goal of the duplication is to find useful abstractions. Sometimes, though, code duplication is really a hint to think differently about a problem. Factoring out a function or class -- finding a new abstraction -- may be incidental to the learning that takes place.

For me, this line from from the second programming-is-terrible post captures this idea perfectly:

... duplicate to find the right abstraction first, then deduplicate to implement it.

My spell checker objects to the word "deduplicate", but I'll allow it.

All of these ideas taken together are the reason that I think copy-and-paste gets an undeservedly bad name. Used properly, it is a valuable programming technique -- essential, really. I've long wanted to write a Big Ball of Mud-style paper about copy-and-paste patterns. There are plenty of good reasons why we write repetitive code and, as @tef says in the two posts I link to above, sometimes leaving duplication in your code is the right thing to do.

One final tribute to repetition for now. While researching this blog post, I ran across a blog entry of mine from October 2016. Apparently, I had just read @tef's Write code that is easy to delete... post and felt an undeniable urge to quote and comment on it. If you read that 2016 post, you'll see that my Writing code that is easy to delete post from last week duplicates it in spirit and, in a few cases, even the details. I swear that I read @tef's post again last week and wrote the new blog entry from scratch, with no memory of the 2016 events. I am perfectly happy with this second act. Sometimes, ideas circle through our brains again, changing us in imperceptible ways. As @tef says, a little redundancy is healthy.


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

January 06, 2019 10:10 AM

Programming Never Feels Easier. You Just Solve Harder Problems.

Alex Honnold is a rock climber who was the first person to "free solo" Yosemite's El Capitan rock wall. In an interview for a magazine, he was asked what it takes to reach ever higher goals. One bit of advice was to "aim for joy, not euphoria". When you prepare to achieve a goal, it may not feel like a big surprise when you achieve it because you prepared to succeed. Don't expect to be overwhelmed by powerful emotions when you accomplish something new; doing so sets too high a standard and can demotivate you.

This paragraph, though, is the one that spoke to me:

Someone recently said to me about running: "It never feels easier--you just go faster." A lot of sports always feel terrible. Climbing is always like that. You always feel weak and like you suck, but you can do harder and harder things.

As a one-time marathoner, never fast but always training to run a PR in my next race, I know what Honnold means. However, I also feel something similar as a programmer. Writing software often seems like a slog that I'm not very good at. I'm forever looking up language features in order to get my code to work, and then I end up with programs that are bulky and fight me at every turn. I refactor and rewrite and... find myself back in the slog. I don't feel terrible all that often, but I am usually a little on edge.

Yet if I compare the programs I write today with ones I wrote 5 or 10 or 30 years ago, I can see that I'm doing more interesting work. This is the natural order. Once I know how to do one thing, I seek tougher problems to solve.

In the article, the passage quoted above is labeled "Feeling awful is normal." I wonder if programming feels more accessible to people who are comfortable with a steady, low-grade intellectual discomfort punctuated by occasional bouts of head banging. Honnold's observation might reassure beginning programmers who don't already know that feeling uneasy is a natural part of pushing yourself to do more interesting work.

All that said, even when I was training for my next marathon, I was always able to run for fun. There was nothing quite like an easy run at sunrise to boost my mood. Fortunately, I am still able to program that way, too. Every once in a while, I like to write code to solve some simple problem I run across on Twitter or in a blog entry somewhere. I find that these interludes recharge me before I battling the next big problem I decide to tackle. I hope that my students can still programming in this way as they advance on to bigger challenges.


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

January 02, 2019 2:22 PM

Writing Code that is Easy to Delete

Last week someone tweeted a link to Write code that is easy to delete, not easy to extend. It contains a lot of great advice on how to create codebases that are easy to maintain and easy to change, the latter being an essential feature of almost any code that is the former. I liked this article so much that I wanted to share some of its advice here. What follows are a few of the many one- and two-liners that serve as useful slogans for building maintainable software, with light commentary.

... repeat yourself to avoid creating dependencies, but don't repeat yourself to manage them.

This line from the first page of the paper hooked me. I'm not sure I had ever had this thought, at least not so succinctly, but it captures a bit of understanding that I think I had. Reading this, I knew I wanted to read the rest of the article.

Make a util directory and keep different utilities in different files. A single util file will always grow until it is too big and yet too hard to split apart. Using a single util file is unhygienic.

This isn't the sort of witticism that I quote in the rest of this post, but its solid advice that I've come to live by over the years. I have this pattern.

Boiler plate is a lot like copy-pasting, but you change some of the code in a different place each time, rather than the same bit over and over.

I really like the author's distinction between boilerplate and copy-and-paste. Copy-and-paste has valuable uses (heresy, I know; more later), whereas boilerplate sucks the joy out of almost every programmer's life.

You are writing more lines of code, but you are writing those lines of code in the easy-to-delete parts.

Another neat distinction. Even when we understand that lines of code are an expense as much as (or instead of) an investment, we know that sometimes we have write more code. Just do it in units that are easy to delete.

A lesson in separating concerns, from Python libraries:

requests is about popular http adventures, urllib3 is about giving you the tools to choose your own adventure.

Layers! I have had users of both of these libraries suggest that the other should not exist, but they serve different audiences. They meet different needs in a way that that more than makes up for the cost of the supposed duplication.

Building a pleasant to use API and building an extensible API are often at odds with each other.

There's nothing earth-shattering in this observation, but I like to highlight different kinds of trade-off whenever I can. Every important decision we make writing programs is a trade-off.

Good APIs are designed with empathy for the programmers who will use it, and layering is realising we can't please everyone at once.

This advice elaborates on the quote earlier to repeat code in order not to create dependencies, but not to manage them. Creating a separate API is one way to avoid dependencies to code that are hard to delete.

Sometimes it's easier to delete one big mistake than try to delete 18 smaller interleaved mistakes.

Sometimes it really is best to write a big chunk of code precisely because it is easy to delete. An idea that is distributed throughout a bunch of functions or modules has to be disentangled before you can delete it.

Becoming a professional software developer is accumulating a back-catalogue of regrets and mistakes.

I'm going to use this line in my spring Programming Languages class. There are unforeseen advantages to all the practice we profs ask students to do. That's where experience comes from.

We are not building modules around being able to re-use them, but being able to change them.

This is another good bit of advice for my students, though I'll write this one more clearly. When students learn to program, textbooks often teach them that the main reason to write a function is that you can reuse it later, thus saving the effort of writing similar code again. That's certainly one benefit of writing a function, but experienced programmers know that there are other big wins in creating functions, classes, and modules, and that these wins are often even more valuable than reuse. In my courses, I try to help students appreciate the value of names in understanding and modifying code. Modularity also makes it easier to change and, yes, delete code. Unfortunately, students don't always get the right kind of experience in their courses to develop this deeper understanding.

Although the single responsibility principle suggests that "each module should only handle one hard problem", it is more important that "each hard problem is only handled by one module".

Lovely. The single module that handles a hard problem is a point of leverage. It can be deleted when the problem goes away. It can be rewritten from scratch when you understand the problem better or when the context around the problem changes.

This line is the heart of the article:

The strategies I've talked about -- layering, isolation, common interfaces, composition -- are not about writing good software, but how to build software that can change over time.

Good software is software that can you can change. One way to create software you can change is to write code that you can easily replace.

Good code isn't about getting it right the first time. Good code is just legacy code that doesn't get in the way.

A perfect aphorism to close to the article, and to perfect way to close this post: Good code is legacy code that doesn't get in the way.


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

December 29, 2018 4:41 PM

No Big Deal

I love this line from Organizational Debt:

So my proposal for Rust 2019 is not that big of a deal, I guess: we just need to redesign our decision making process, reorganize our governance structures, establish new norms of communication, and find a way to redirect a significant amount of capital toward Rust contributors.

A solid understatement usually makes me smile. Decision-making processes, governance structure, norms of communication, and compensation for open-source developers... no big deal, indeed. We all await the results. If the results come with advice that generalizes beyond a single project, especially the open-source compensation thing, all the better.

Communication is a big part of the recommendation for 2019. Changing how communication works is tough in any organization, let alone an organization with distributed membership and leadership. In every growing organization there eventually comes the time for intentional systems of communication:

But we've long since reached the point where coordinating our design vision by osmosis is not working well. We need an active and intentional circulatory system for information, patterns, and frameworks of decision making related to design.

I'm not a member of the Rust community, only an observer. But I know that the language inspires some programmers, and I learned a bit about its tool chain and community support a couple of years ago when an ambitious student used it successfully to implement his compiler in my course. It's the sort of language we need, being created in what looks to be an admirable way. I wish the Rust team well as they tackle their organizational debt and tackle their growing pains.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

November 28, 2018 1:56 PM

If it matters enough to be careful, it matters enough to build a system.

In Quality and Effort, Seth Godin reminds us that being careful can take us only so far toward the quality we seek. Humans make mistakes, so we need processes and systems in place to help us avoid them. Near the end of the post, he writes:

In school, we harangue kids to be more careful, and spend approximately zero time teaching them to build better systems instead. We ignore checklists and processes because we've been taught that they're beneath us.

This paragraph isolates one of the great powers we can teach our students, but also a glaring weakness in how most of us actually teach. I've been a professor for many years now, and before that I was a student for many years. I've seen a lot of students succeed and a few not do as well as they or I had hoped. Students who are methodical, patient, and disciplined in how they read, study, and program are much more likely to be in the successful group.

Rules and discipline sometimes get a bad rap these days. Creativity and passion are our catchwords. But dull, boring systems are often the keys that unlock the doors to getting things done and moving on to learn and do cooler things.

Students occasionally ask me why I slavishly follow the processes I teach them, whether it's a system as big as test-first development and refactoring or a process as simple as the technique for creating NFAs and converting them to DFAs. I tell them that I don't always trust myself but that I do trust the system: it almost always leads me to a working solution. Sure, in this moment or that I might be fine going off script, but... Good habits generate positive returns, while freewheeling it too often lets an error sneak in. (When I go off script in class, they too often get to see just that!)

We do our students a great favor when when we help them learn systems that work. Following a design recipe or something like it may be boring, but students who learn to follow it develop stronger programming skills, enjoy the success of getting projects done successfully, and graduate on to more interesting problems. As the system becomes ingrained as habit, they usually begin to appreciate it as an enabler of their success.

I agree with Godin: If it matters enough to be careful, then it matters enough to build (or learn) a system.


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

November 23, 2018 8:26 AM

The Peter Principle of Software Growth

This morning I read Against Software Development, which considers two tragedies of software development and a moral exhortation. One of the tragedies:

Software grows until it exceeds our capacity to understand it.

This observation reminds me of the Peter Principle from business management, which points out that people in a business are promoted until to they reach a level at which they are incompetent. Success in the hierarchy ends when people find that their skills no longer match the needs of their job.

We see something similar in software. We write a program to solve a problem. At this point, we understand the program completely so, when we see an opportunity for a new feature, we extend it. We still understand the system, so we add a bit more complexity, either implementing a new subtask or elaborating an existing feature with more detail. This process keeps happening until... we don't understand the program any more. Or, more likely, we understand it at a macro level but no longer grok all of the interconnections and dependencies among components. The result is Peter-like: the program stops growing. The root cause is not the incompetence of developers, but a fear born out complexity.

Having a system under a comprehensive set of tests can help stave off this fear. With careful attention, some time, and energy, we can use refactoring can sometimes reverse the entropy that sets in over time. But often the practicalities of organizations leave us with a big piece of software that we don't really understand, a system that can't grow or be changed to fit the evolving context in which it operates.

Many companies then find themselves in an odd situation: ossifying the organization's processes and procedures in order to stay in conformance with a piece of software its developers no long understand. Software rigidity becomes organizational rigidity.

Stay vigilant! With good development practices, perhaps you can push the point of no understanding farther into the future. But be ready for the day. It will probably arrive, sooner or later.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

October 05, 2018 3:39 PM

Why Patterns Failed and Why You Should Care

Beds are useful. I enjoyed my bed at the hotel last night. But you won't find a pattern called bed in A Pattern Language, and that's because we don't have a problem with beds. Beds are solved. What we have a problem with is building with beds. And that's why, if you look in A Pattern Language, you'll find there are a number of patterns that involve beds.

Now, the analogy I want to make is, basically, the design patterns in the book Design Patterns are at the same level as the building blocks in the book A Pattern Language. So Bridge, which is one of the design patterns, is the same kind of thing as column. You can call it a pattern, but it's not really a pattern that gets at the root problem we're trying to solve. And if Alexander had written a book that had a pattern called Bed and another one called Chair, I imagine that that book would have failed and not inspired all of the people that the actual book did inspire. So that, I claim, is why patterns failed.

Those two nearly-sequential paragraphs are from Patterns Failed. Why? Should We Care?, a talk Brian Marick gave at Deconstruct 2017. It's a good talk. Marick's provocative claim that, as an idea, software patterns failed is various degrees of true and false depending on how you define 'patterns' and 'failed'. It's hard to declare the idea an absolute failure, because a lot of software developers and UI designers use patterns to good effect as a part of their work every day. But I agree with Brian that software patterns failed to live up to their promise or to the goals of the programmers who worked so hard to introduce Christopher Alexander's work to the software community. I agree, too, that the software pattern community's inability to document and share patterns at the granularity that made Alexander's patterns so irresistible is a big part of why.

I was a second- or third-generation member of the patterns community, joining in after Design Patterns had been published and, like Marick, I worked mostly on the periphery. Early on I wrote patterns that related to my knowledge-based systems work. Much of my pattern-writing, though, was at the level of elementary patterns, the patterns that novice programmers learn when they are first learning to program. Even at that level, the most useful patterns often were ones that operated up one level from the building blocks that novices knew.

Consider Guarded Linear Search, from the Loop Patterns paper that Owen Astrachan and I workshopped at PLoP 1998. It helps beginners learn how to arrange a loop and an if statement in a way that achieves a goal. Students in my beginning courses often commented how patterns like this one helped them write programs because, while they understood if statements and for statements and while statements, they didn't always know what to do with them when facing a programming task. At that most elementary level, the Guarded Linear Search pattern was a pleasing -- and useful -- whole.

That said, there aren't many "solved problems" for beginners, so we often wrote patterns that dropped down to the level of building blocks simply to help novices learn basic constructs. Some of the Loop Patterns paper does that, as does Joe Bergin's Patterns for Selection. But work in the elementary patterns community would have been much more valuable, and potentially had more effect, if we had thought harder about how to find and document patterns at the level of Alexander's patterns.

Perhaps the patterns sub-community in which I've worked in which best achieved its goals was the pedagogical patterns community. These are not software patterns but rather patterns of teaching techniques. They document solutions to problems that teachers face every day. I think I'd be willing to argue that the primary source of pedagogical patterns' effectiveness is that these solutions combine more primitive building blocks (delivery techniques, feedback techniques, interaction techniques) in a way that make learning and instruction both more effective and more fun. As a result, they captured a lot of teachers' interest.

I think that Marick's diagnosis also points out the error in a common criticism of software patterns. Over the years, we often heard folks say that software patterns existed only because people used horrible languages like C++ and Java. In a more powerful language, any purported pattern would be implemented as a language primitive or could be made a primitive by writing a macro. But this misses the point of Alexander's insight. The problem in software development isn't with inheritance and message passing and loops, just as the problem in architecture isn't with beds and windows and space. It's with finding ways to arrange these building blocks in a way that's comfortable and nice and, to use Alexander's term, "life-giving". That challenge exists in all programming languages.

Finally, you probably won't be surprised to learn that I agree with Marick that we should all care that software patterns failed to live up to their promise. Making software is fun, but it's also challenging. Alexander's idea of a pattern language is one way that we might help programmers do their jobs better, enjoy their jobs more, and produce software that is both functional and habitable. The first pass was a worthy effort, and a second pass, informed by the lessons of the first, might get us closer to the goal.

Thanks to Brian for giving this talk and to the folks at Deconstruct for posting it online. Go watch it.


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

October 01, 2018 7:12 PM

Strange Loop 4: The Quotable Wadler

Philip Wadler is a rockstar to the Strange Loop crowd. His 2015 talk on propositions as types introduced not a few developers to one of computer science's great unities. This year, he returned to add a third idea to what is really a triumvirate: categories. With a little help from his audience, he showed that category theory has elements which correspond directly to ...

  • logical 'and', which models the record (or tuple, or pair) data type
  • logical 'or', which models the union (or variant record) data type
  • a map, which models the function data type
What's more, the product/sum dual models De Morgan's laws, but with more structure, which enables it to model sets beyond the booleans!

Wadler is an entertaining teacher; I recommend the video of his talk! But he is also as quotable as any CS prof I've encountered in a long while. Here is a smattering of his great lines from "Categories for the Working Hacker":

If you can use math to do something, do it. It will make your life better.

That's the great thing about math. It lets you see something obvious after only thirty or forty years.

Pick your favorite algebra. If you don't have one, get one.

Let's do that in Java. That's what you should always do when you learn a new idea: do it in Java.

That's what category theory is really about: avoiding traffic jams.

Sums are the secret origin of folds.

If you don't understand this, I don't mind, because it's Java.

While watching the presentation, I created a one-liner of my own: Surprise! If you do something that matches exactly what Haskell does, Haskell code will be much shorter than Java code.

This was a very good talk; I enjoyed it quite a bit. However, I also left the room with a couple of nagging questions. The talk was titled "Categories for the Working Hacker", and it did a nice job of presenting some basic ideas from category theory in a way that most any developer could understand, even one without much background in math. But... How does this knowledge make one a better hacker? Armed with this new, entertaining knowledge, what are software developers able to do that they couldn't do before?

I have my own ideas for answers to these questions, but I would love to hear Wadler's take.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

August 09, 2018 1:03 PM

Gerald Weinberg Has Passed Away

I just read on the old Agile/XP mailing list that Jerry Weinberg passed away on Tuesday, August 7. The message hailed Weinberg as "one of the finest thinkers on computer software development". I, like many, was a big fan of work.

My first encounter with Weinberg came in the mid-1990s when someone recommended The Psychology of Computer Programming to me. It was already over twenty years old, but it captivated me. It augmented years of experience in the trenches developing computer software with a deep understanding of psychology and anthropology and the firm but gentle mindset of a gifted teacher. I still refer back to it after all these years. Whenever I open it up to a random page, I learn something new again. If you've never read it, check it out now. You can buy the ebook -- along with many of Weinberg's books -- online through LeanPub.

After the first book, I was hooked. I never had the opportunity to attend one of Weinberg's workshops, but colleagues lavished them with praise. I should have made more of an effort to attend one. My memory is foggy now, but I do think I exchanged email messages with him once back in the late 1990s. I'll have to see if I can dig them up in one of my mail archives.

Fifteen years ago or so, I picked up a copy of Introduction to General Systems Thinking tossed out by a retiring colleague, and it became the first in a small collection of Weinberg books now on my shelf. As older colleagues retire in the coming years, I would be happy to salvage more titles and extend my collection. It won't be worth much on the open market, but perhaps I'll be able to share my love of Weinberg's work with students and younger colleagues. Books make great gifts, and more so a book by Gerald Weinberg.

Perhaps I'll share them with my non-CS friends and family, too. A couple of summers back, my wife saw a copy of Are Your Lights On?, a book Weinberg co-wrote with Donald Gause, sitting on the floor of my study at home. She read it and liked it a lot. "You get to read books like that for your work?" Yes.

I just read Weinberg's final blog entry earlier this week. He wasn't a prolific blogger, but he wrote a post every week or ten days, usually about consulting, managing, and career development. His final post touched on something that we professors experience at least occasionally: students sometimes solve the problems we et before them better than we expected, or better than we ourselves can do. He reminded people not to be defensive, even if it's hard, and to see the situation as an opportunity to learn:

When I was a little boy, my father challenged me to learn something new every day before allowing myself to go to bed. Learning new things all the time is perhaps the most important behavior in my life. It's certainly the most important behavior in our profession.

Weinberg was teaching us to the end, with grace and gratitude. I will miss him.

Oh, and one last personal note: I didn't know until after he passed that we shared the same birthday, a few years apart. A meaningless coincidence, of course, but it made me smile.


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

July 31, 2018 4:23 PM

Software Projects, Potential Employers, and Memories

I spent a couple of hours this morning at a roundtable discussion listening to area tech employers talk about their work and their companies' needs. It was pretty enjoyable (well, except perhaps for the CEO who too frequently prefaced his remarks with "What the education system needs to understand is ..."). To a company, they all place a lot of value on the projects that job candidates have done. Their comments reminded me of an old MAA blog post in which a recent grad said:

During the fall of my junior year, I applied for an internship at Red Ventures, a data analytics and technology company just outside Charlotte. Throughout the rigorous interview process, it wasn't my GPA that stood out. I stood out among the applicants, in part, because I was able to discuss multiple projects I had taken ownership of and was extremely passionate about.

I encourage this mentality in my students, though I think "passionate about" is too strong a condition (not to mention cliché). Students should have a few projects that they are interested in, or proud of, or maybe just completed.

Most of the students taking my compiler course this fall won't be applying for a compiler job when they graduate, but they will have written a compiler as part of a team. They will have met a spec, collaborated on code, and delivered a working product. That is evidence of skill, to be sure, but also of hard work and persistence. It's a significant accomplishment.

The students who take our intelligent systems course or our real-time embedded systems will be able to say the same thing. Some students will also be able to point to code they wrote for a club or personal projects. They key is to build things, care about them, and "deliver", whatever that means in the context of that particular project.

I made note of one new piece of advice to give our students, offered by a former student I mentioned in a blog post many years ago who is now head of a local development team for mobile game developer Jam City: Keep all the code you write. It can be a GitHub repo, as many people now recommend, but it doesn't have to be. A simple zip file organized by courses and projects can be enough. Such a portfolio can show prospective employers what you've done, how you've grown, and how much you care about the things you make. It can say a lot.

You might even want to keep all that code for Future You. I'm old enough that it was difficult to keep digital copies of all the code I wrote in college. I have a few programs from my undergrad days and a few more from grad school, which have migrated across storage media as time passed, but I missing much of my class work as a young undergrad and all of the code I wrote in high school. I sometimes wish I could look back at some of that code...


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

July 28, 2018 11:37 AM

Three Things I Read This Morning

Why I Don't Love Gödel, Escher, Bach

I saw a lot of favorable links to this post a while back and finally got around to it. Meh. I generally agree with the author: GEB is verbose in places, there's a lot of unnecessary name checking, and the dialogues that lead off each chapter are often tedious. I even trust the author's assertion that Hofstadter's forays beyond math, logic, and computers are shallow.

So what? Things don't have to be perfect for me to like them, or for them to make me think. GEB was a swirl of ideas that caused me to think and helped me make a few connections. I'm sure if I read the book now that I would feel differently about it, but reading it when I did, as an undergrad CS major thinking about AI and the future, it energized me.

I do thank the author for his pointer (in a footnote) to Vi Hart's wonderful Twelve Tones. You should watch it. Zombie Schonberg!

The Web Aesthetic

This post wasn't quite what I expected, but even a few years old it has something to say to web designers today.

Everything on the web ultimately needs to degrade down to plain text (images require alt text; videos require transcripts), so the text editor might just become the most powerful app in the designer's toolbox.

XP Challenge: Compilers

People outside the XP community often don't realize how seriously the popularizers of XP explored the limitations of their own ideas. This page documents one of several challenges that push XP values and practices to the limits: When do they break down? Can they be adapted successfully to the task? What are the consequences of applying them in such circumstances?

Re-reading this old wiki page was worth it if only for this great line from Ron Jeffries:

The point of XP is to win, not die bravely.

Yes.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Patterns, Software Development

July 17, 2018 2:32 PM

Get Attached to Solving Problems for People

In Getting Critiqued, Adam Morse reflects on his evolution from art student to web designer, and how that changed his relationship with users and critiques. Artists create things in which they are, at some level, invested. Their process matters. As a result, critiques, however well-intentioned, feel personal. The work isn't about a user; it's about you. But...

... design is different. As a designer, I don't matter. My work doesn't matter. Nothing I make matters in the context of my process. It's all about the people you are building for. You're just trying to solve problems for people. Once you realize this, it's the most liberating thing.

Now, criticism isn't really about you as artist. It's about how well the design meets the needs of the user. With that in mind, the artist can put some distance between himself or herself and think about the users. That's probably what the users are paying for anyway.

I've never been a designer, but I was fortunate to learn how better to separate myself from my work by participating in the software patterns community and its writers' workshop format. From the workshops, I came to appreciate the value of providing positive and constructive feedback in a supportive way. But I also learned to let critiques from others be about my writing and not about me. The ethos of writers' workshops is one of shared commitment to growth and so creates as supportive framework as possible in which to deliver suggestions. Now, even when I'm not in such an conspicuously supportive environment, I am better able to detach myself from my work. It's never easy, but it's easier. This mindset can wear off a bit over time, so I find an occasional inoculation via PLoP or another supportive setting to be useful.

Morse offers another source of reminder: the designs we create for the web -- and for most software, too-- are not likely to last forever. So...

Don't fall in love with borders, gradients, a shade of blue, text on blurred photos, fancy animations, a certain typeface, flash, or music that autoplays. Just get attached to solving problems for people.

That last sentence is pretty good advice for programmers and designers alike. If we detach ourselves from our specific work output a bit and instead attach ourselves to solving problems for other people, we'll be able to handle their critiques more calmly. As a result, we are also likely to do better work.


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

July 16, 2018 2:08 PM

Code is better when written with collaboration in mind

In Collaboration considered helpful, Ken Perlin writes:

In the last few days I have needed to make the transition from writing a piece of software all on my own to bringing in a collaborator. Which means I've needed to go into my code and change a lot of things, in order to make everything easier to understand and communicate.

There was a part of me that felt grumpy about this. After all, I already knew exactly where everything was before this other person ever came on board.

But then I looked at the changes I had made, and realized that the entire system was now much cleaner, more robust, and far easier to maintain. Clearly there is something intrinsically better about code that is designed for collaboration.

Knowing that our code must communicate with other people causes us to write better code.

The above is an usually large quotation from another post for me. Even so, Perlin makes a bigger point than this, so read the entire post.

By the way, Perlin's blog has probably been the happiest addition I've made to my blog reader over the past year. He writes short, thoughtful posts everyday, on topics that include programming, teaching, academic life, and virtual reality. I enjoy almost all of them and always look forward to the next one.


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

June 17, 2018 9:52 AM

Sometimes, Evolution Does What No Pivot Can

From an old New Yorker article about Spotify:

YouTube, which is by far the largest streaming-music site in the world (it wasn't designed that way--that's just what it became)...

Companies starting in one line of business and evolving into something else is nothing new. I mean, The Connecticut Leather Company became Coleco and made video game consoles. But there's something about software that make this sort of evolution seem so normal. We build a computer system to solve one problem and find that our users -- who have needs and desires that neither we nor they fully comprehend -- use it to solve a different problem. Interesting times. Don't hem yourself in, and don't hem your software in, or the people who use it.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

May 29, 2018 3:41 PM

Software as Adaptation-Executer, Not Fitness-Maximizer

In Adaptation-Executers, not Fitness-Maximizers, Eliezer Yudkowsky talks about how evolution has led to human traits that may no longer be ideal in the our current environment. He also talks about tools, though, and this summary sentence made me think of programs:

So the screwdriver's cause, and its shape, and its consequence, and its various meanings, are all different things; and only one of these things is found within the screwdriver itself.

I often fall victim to thinking that the meaning of software is at least somewhat inherent in its code, but that really is what the designer intended as its use -- a mix of what Yudkowsky calls its cause and its consequence. These are things that exist only in the mind of the designer and the user, not in the computational constructs that constitute the code.

When approaching new software, especially a complex piece of code with many parts, it's helpful to remember that it doesn't really have objective meaning or consequences, only those intended by its designers and those exercised by its users. Over time, the users' conception tends to drive the designers' conception as they put the software to particular uses and even modify it to better suit these new uses.

Perhaps software is best thought of as an adaptation-executer, too, and not as a fitness-maximizer.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

May 18, 2018 1:24 PM

Sharing Control

Sidney Lumet, in his book Making Movies, writes:

Arthur Miller's first, and I think, only novel, Focus, was, in my opinion, every bit as good as his first produced play, All My Sons. I once asked him why, if he was equally talented in both forms, he chose to write plays. Why would he give up the total control of the creative process that a novel provides to write instead for communal control, where a play would first go into the hands of a director and then pass into the hands of a cast, set designer, producer, and so forth? His answer was touching. He loved seeing what his work evoked in others. The result could contain revelations, feelings, and ideas that he never knew existed when he wrote the play. That's what he hoped for.

Writing software for people to use is something quite different from writing a play for audiences to watch, but this paragraph brought to mind experiences I had as a grad student and new faculty member. As a part of my doctoral work, I implemented a expert system shells for a couple of problem-solving styles. Experts and grad students in domains such as chemical engineering, civil engineering, education, manufacturing, and tax accounting used these shells to build expert systems in their domains. I often found myself in the lab with these folks as they used my tools. I learned a lot by watching them and discussing with them the languages implemented in the tools. Their comments and ideas sometimes changed how I thought about the languages and tools, and I was able to fold some of these changes back into the systems.

Software design can be communal, too. This is, of course, one of the cornerstones of agile software development. Giving up control can help us write better software, but it can also be a source of the kind of pleasure I imagine Miller got from working to bring his plays to life on stage.


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

May 09, 2018 4:02 PM

Middles

In an old blog post promoting his book on timing, Daniel Pink writes:

... Connie Gersick's research has shown that group projects rarely progress in a steady, linear way. Instead, at the beginning of a project, groups do very little. Then at a certain moment, they experience a sudden burst of activity and finally get going. When is that moment? The temporal midpoint. Give a team 34 days, they get started in earnest on day 17. Give a team 11 days, they get really get going on day 6. In addition, there’s other research showing that being behind at the midpoint--in NBA games and in experimental settings--can boost performance in the second half.

So we need to recognize midpoints and try to use them as a spark rather than a slump.

I wonder if this research suggests that we should favor shorter projects over longer ones. If most of us start going full force only at the middle of our projects, perhaps we should make the middle of our projects come sooner.

I'll admit that I have a fondness for short over long: short iterations over long iterations in software development, quarters over semesters in educational settings, short books (especially non-fiction) over long books. Shorter cycles seem to lead to higher productivity, because I spend more time working and less time ramping up and winding down. That seems to be true for my students and faculty colleagues, too.

In the paragraph that follows the quoted passage, Pink points inadvertently to another feature of short projects that I appreciate: more frequent beginnings and endings. He talks about the poignancy of endings, which adds meaning to the experience. On the other end of the cycle are beginnings, which create a sense of newness and energy. I always look forward to the beginning of a new semester or a new project for the energy it brings me.

Agile software developers know that, on top of these reasons, short projects offer another potent advantage: more opportunities to take stock of what we have learned and feed that learning back into what we do.


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

April 29, 2018 8:04 AM

Bugs Keep Me Humble

Joshua Bloch, in this oldie but goodie:

The general lesson that I take away from this bug is humility: It is hard to write even the smallest piece of code correctly, and our whole world runs on big, complex pieces of code.

Having just written a small interpreter for my programming languages course, I, too, am feeling humble. Even in code that couldn't possibly go wrong, I had a small bug that bedeviled me for fifteen minutes. (You have to dereference those bindings in order to get the cells you want to mutate...) The experience is good preparation for a couple of software projects I hope to do this summer and for my compiler course this fall.

Oh, and Bloch's old post reminds me that it may be a good time to work through "Programming Pearls" again. It's been a while.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

March 29, 2018 3:05 PM

Heresy in the Battle Between OOP and FP

For years now, I've been listening to many people -- smart, accomplished people -- feverishly proclaim that functional programming is here to right the wrongs of object-oriented programming. For many years before that, I heard many people -- smart, accomplished people -- feverishly proclaim that object-oriented programming was superior to functional programming, an academic toy, for building real software.

Alas, I don't have a home in the battle between OOP and FP. I like and program in both styles. So it's nice whenever I come across something like Alan Kay's recent post on Quora, in response to the question, "Why is functional programming seen as the opposite of OOP rather than an addition to it?" He closes with a paragraph I could take on as my credo:

So: both OOP and functional computation can be completely compatible (and should be!). There is no reason to munge state in objects, and there is no reason to invent "monads" in FP. We just have to realize that "computers are simulators" and figure out what to simulate.

As in many things, Kay encourages to go beyond today's pop culture of programming to create a computational medium that incorporates big ideas from the beginning of our discipline. While we work on those ideas, I'll continue to write programs in both styles, and to enjoy them both. With any luck, I'll bounce between mindsets long enough that I eventually attain enlightenment, like the venerable master Qc Na. (See the koan at the bottom of that link.)

Oh: Kay really closes his post with

I will be giving a talk on these ideas in July in Amsterdam (at the "CurryOn" conference).

If that's not a reason to go to Amsterdam for a few days, I don't know what is. Some of the other speakers looks pretty good, too.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

March 23, 2018 3:45 PM

A New Way to Design Programming Languages?

Greg Wilson wrote a short blog post recently about why JavaScript isn't suitable for teaching Data Carpentry-style workshops. In closing, he suggests an unusual way to design programming languages:

What I do know is that the world would be a better place if language designers adopted tutorial-driven design: write the lessons that introduce newcomers to the language, then implement the features those tutorials require.

That's a different sort of TDD than I'm used to...

This is the sort of idea that causes me to do a double or triple take. At first, it has an appealing ring to it, when considering how difficult it is to teach most programming languages to novices. Then I think a bit and decide that it sounds crazy because, really, are we going to hamstring our languages by focusing on the struggles of beginners? But then it sits in my mind for a while and I start to wonder if we couldn't grow a decent language this way. It's almost like using the old TDD to implement new the TDD.

The PLT Scheme folks have designed a set of teaching languages that enable beginners to grow into an industry-strength language. That design project seems to have worked from the outsides in, with a target language in mind while designing the teaching languages. Maybe Wilson's idea of starting at the beginning isn't so crazy after all.


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

February 26, 2018 3:55 PM

Racket Love

Racket -- "A Programmable Programming Language" -- is the cover story for next month's Communications of the ACM. The new issue is already featured on the magazine's home page, including a short video in which Matthias Felleisen explains the idea of code as more than a machine artifact.

My love of Racket is no surprise to readers of this blog. Still one of my favorite old posts here is The Racket Way, a write-up of my notes from Matthew Flatt's talk of the same name at StrangeLoop 2012. As I said in that post, this was a deceptively impressive talk. I think that's especially fitting, because Racket is a deceptively impressive language.

One last little bit of love from a recent message to the Racket users mailing list... Stewart Mackenzie describes his feelings about the seamless interweaving of Racket and Typed Racket via a #lang directive:

So far my dive into Racket has positive. It's magical how I can switch from untyped Racket to typed Racket simply by changing #lang. Banging out my thoughts in a beautiful lisp 1, wave a finger, then finger crack to type check. Just sublime.

That's what you get when your programming language is as programmable as your application.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

February 16, 2018 2:54 PM

Old Ideas and New Words

In this Los Angeles Review of Books interview, novelist Jenny Offill says:

I was reading a poet from the Tang dynasty... One of his lines from, I don't know, page 812, was "No new feelings". When I read that I laughed out loud. People have been writing about the same things since the invention of the written word. The only originality comes from the language itself.

After a week revising lecture notes and rewriting a recruiting talk intended for high school students and their parents, I know just what Offill and that Tang poet mean. I sometimes feel the same way about code.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

February 12, 2018 4:03 PM

How Do We Choose The Programming Languages We Love?

In Material as Metaphor, the artist Anni Albers talks about how she came to choose media in which she worked:

How do we choose our specific material, our means of communication? "Accidentally". Something speaks to us, a sound, a touch, hardness or softness, it catches us and asks us to be formed. We are finding our language, and as we go along we learn to obey their rules and their limits. We have to obey, and adjust to those demands. Ideas flow from it to us and though we feel to be the creator we are involved in a dialogue with our medium. The more subtly we are tuned to our medium, the more inventive our actions will become. Not listening to it ends in failure.

This expresses much the way I feel about different programming languages and styles. I can like them all, and sometimes do! I go through phases when one style speaks to me more than another, or when one language seems to be in sync with how I am thinking. When that happens, I find myself wanting to learn its rules, to conform so that I can reach a point where I feel creative enough to solve interesting problems in the language.

If I find myself not liking a language, it's usually because I'm not listening to it; I'm fighting back. When I first tried to learn Haskell, I refused to bend to its style of functional programming. I had worked hard to grok FP in Scheme, and I was so proud of my hard-won understanding that I wanted to impose it on the new language. Eventually, I retreated for a while, returned more humbly, and finally came to appreciate Haskell, if not master it deeply.

My experience with Smalltalk went differently. One summer I listened to what it was telling me, slowly and patiently, throwing code away and starting over several times on an application I was trying to build. This didn't feel like a struggle so much as a several-month tutoring session. By the end, I felt ideas flowing through me. I think that's the kind of dialogue Albers is referring to.

If I want to master a new programming language, I have to be willing to obey its limits and to learn how to use its strengths as leverage. This can be a conscious choice. It's frustrating when that doesn't seem to be enough.

I wish I could always will myself into the right frame of mind to learn a new way of thinking. Albers reminds us that often a language speaks to us first. Sometimes, I just have to walk away and wait until the time is right.


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

January 22, 2018 3:50 PM

Same Footage, Different Film

In In the Blink of an Eye, Walter Murch tells the story of human and chimpanzee DNA, about how the DNA itself is substantially the same and how the sequencing, which we understand less well, creates different beings during the development of the newborn. He concludes by bringing the analogy back to film editing:

My point is that the information in the DNA can be seen as uncut film and the mysterious sequencing as the editor. You could sit in one room with a pile of dailies and another editor could sit in the next room with exactly the same footage and both of you could make different films out of the same material.

This struck me as quite the opposite of what programmers do. When given a new problem and a large language in which to solve it, two programmers can choose substantially different source material and yet end up telling the same story. Functional and OO programmers, say, may decompose the problem in a different way and rely on different language features to build their solutions, but in the end both programs will solve the same problem and meet the same user need. Like the chimp and the human, though, the resulting programs may be better adapted for living in different environments.


Posted by Eugene Wallingford | Permalink | Categories: General, Software Development

December 20, 2017 3:51 PM

== false

While grading one last project for the semester, I ran across this gem:

    if checkInputParameters() == False:
       [...]

This code was not written by a beginning programmer, but a senior who likely will graduate in May. Sigh.

I inherited this course late in the semester, so it would be nice if I could absolve myself of responsibility for allowing a student to develop such a bad habit. But this isn't the first time I've seen this programming pattern. I've seen it in my courses and in other faculty's courses, in first-year courses and fourth-year courses. In fact, I was so certain that I blogged about the pattern before that I spent several minutes trolling the archive. Alas, I never found the entry.

Don't let anyone tell you that Twitter can't be helpful. Within minutes of tweeting my dismay, two colleagues suggested new strategies for dealing with this anti-pattern.

Sylvain Leroux invoked Star Trek:

James T. Kirk "Kobayashi Maru"-style solution: Hack CPython to properly parse that new syntax:

unless checkInputParameters(): ...

Maybe I'll turn this into a programming exercise for the next student in my compiler class who wanders down the path of temptation. Deep in my heart, though, I know that enterprising programmers will use the new type of statement to write this:

    unless checkInputParameters() == True:
       [...]

Agile Hulk suggested a fix:

    if (checkInputParameters() == False) == True:

This might actually be a productive pedagogical tack to follow: light-hearted and spot on, highlighting the anti-pattern's flaw by applying it to its own output. ("Anti-pattern eats its own dog food.") With any luck, some students will be enlightened, Zen-like. Others will furrow their brow and say "What?"

... and even if we look past the boolean crime in our featured code snippet, we really ought to take on that function name. 'Tis the season, though, and the semester is over. I'll save that rant for another time.


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

November 25, 2017 7:52 AM

Sure, In the End, It's Just Objects and Functions

After implementing the patterns from James Noble's Arguments and Results, Gregory Brown reflects:

After taking a look at the finished Turtle object, I did wonder a little bit about whether the idea of a curried object in Ruby is nothing more than an ordinary object making use of object composition. However, because the name of the pattern is helpful for describing the intent of this sort of object in a succinct way, it may be a good label for us to use when discussing the merits of different design options.

In the end it is, indeed, all just objects, or functions, or whatever the primitives structures are in your programming style du jour. The value of design patterns in any styles lies in teaching us stereotypical patterns of usage, the web of objects or functions we might not have thought of in the course of design. Once we know about the patterns, the names become a valuable part of the vocabulary we use to talk about design.

I know that Brown's blog entry is six years old, that Noble's paper is seventeen, and that talking about design patterns is passé in many circles. But I still find the notion of patterns and pattern languages to be immensely useful, and even in 2017 I hear people express surprise at patterns are just commonsense or bad design dressed up in fancy writing. That makes me sad. We need more descriptions of experts' implicit holistic design knowledge, not fewer.

In closing, though, please don't read my reaction here as a diss of Brown's blog entry. His two entries on Noble's patterns do a nice job showing how these patterns can improve a Ruby program and exploring the trade-offs between the "before" and "after" versions of the code. I hope that he bring his Practicing Ruby project back to life.


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

November 20, 2017 2:58 PM

Tests That Protect Your Code From Without

I recently ran across an old post from Spotify about how the confluence of Spotify's generous policy for usernames, the oddities of Unicode, and a change in standard Python libraries led to a situation in which a person could hijack an existing username. The post explains how Spotify tracked down the problem and fixed it -- a good read.

The paragraph before the closing "Some Take-Aways" section says:

So changes in the standard python library from one python version to the next introduced a subtle bug in twisted's nodepre.prepare() function which in turn introduced a security issue in Spotify's account creation.

... which, to my mind, hints at a bonus takeaway not listed in the closing. It would really have been nice to have had a test that noticed when nodeprep's method for canonicalizing (ugh) usernames was no longer idempotent.

Not having such a test is understandable. I don't write tests for all or even many of the library functions I use. This means trusting the creators of the libraries I use. (It also means choosing libraries judiciously.) In this case, there wasn't even a bug in twisted's original code; a change in Python introduced one. It is hard to anticipate when a language upgrade will create a bug in a library that I am using.

However, when something like this occurs, I find that it is a good time to add a test. This bug exposed just how important it is for the code to ensure idempotence when lower-casing a username. A new test or two can protect the code base from unexpected errors from without without placing an unreasonable burden on me as a developer. And those tests give me peace of mind, which is usually more than worth an extra millisecond when running my tests.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

October 31, 2017 3:44 PM

Chuck Moore, Extreme Programmer

If you have read any of Chuck Moore's work, you know that he is an extreme programmer in the literal sense of the word: a unique philosophy that embraces small, fast, self-contained programs in a spare language and an impressive development environment. But as I read the opening sections of Moore's book Programming a Problem-Oriented Language, I began to mistake him for an XP-style extreme programmer.

Here is You Aren't Gonna Need It or, as Moore says, Do Not Speculate!:

Do not put code in your program that might be used. Do not leave hooks on which you can hang extensions. The things you might want to do are infinite; that means that each one has 0 probability of realization. If you need an extension later, you can code it later - and probably do a better job than if you did it now. And if someone else adds the extension, will they notice the hooks you left? Will you document that aspect of your program?

Moore also has a corollary called Do It Yourself!, which encourages you, in general, to write your own subroutines rather than import one a canned subroutine from a library. That doesn't sound like Doing the Simplest Thing That Can Work, but his intent is similar: an external routine is a dependency, and it probably doesn't match the specific needs of the problem you are solving. Indeed, Moore closes this section with:

Let me take a stand: I can't solve the problems of the world. With luck, I can write a good program.

That could well be the manifesto of XP.

In the next section, a preview of the rest of the book, Moore tells his readers that they won't find flowcharts in the pages to come documenting the algorithms he describes:

I've never liked them, for they seem to include a useless amount of information - either too little or too much. Besides they imply a greater rigidity in program structure than usually exists. I will be quite specific about what I think you should do and how you should do it. But I will use words, and not diagrams. I doubt that you would give a diagram the attention it deserved, anyway. Or that I would in preparing it.

Other than using a few words, he lets the code stands for itself. Documentation would not add enough value to outweigh the cost of preparing it, or reading it. Usually, the best thing to do with Moore's books is to Listen To The Code: settle into your Forth environment, type the code in, run it, and learn from it.

There is no accounting for my weird fascination with stack-based languages. Chuck Moore always give me more to think about than I expected. I suspect that he would be at odds with some of the practices encouraged by XP, but I often feel the spirit of XP in his philosophy.


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

October 12, 2017 3:35 PM

Sometimes, We Need to Make a Better Tool

I learned about a couple of cool CLI tools from Nikita Sobolev's Using Better CLIs. hub and tig look like they may be worth a deeper look. This article also reminded me of one of the examples in the blog entry I rmed the other day. It reflects a certain attitude about languages and development.

One of the common complaints about OOP is that what would be a single function in other programming styles usually ends up distributed across multiple classes in an OO program. For example, instead of:

    void draw(Shape s) {
       case s of
          Circle : [code for circle]
          Square : [code for square]
          ...
    }
the code for the individual shapes ends up in the classes for Circle, Square, and so on. If you have to change the drawing code for all of the shapes, you have to track down all of the classes and modify them individually.

This is true, and it is a serious issue. We can debate the relative benefits and costs of the different designs, of course, but we might also think about ways that our development tools can help us.

As a grad student in the early 1990s, I worked in a research group that used VisualWorks Smalltalk to build all of its software. Even within a single Smalltalk image, we faced this code-all-over-the-place problem. We were adding methods to classes and modifying methods all the time as part of our research. We spent a fair amount of time navigating from class to class to work on the individual methods.

Eventually, one of my fellow students had an epiphany: we could write a new code browser. We would open this browser on a particular class, and the browser would provide a pane listing and all of its subclasses, and all of their subclasses. When we selected a method in the root class, the browser enabled us to click on any of the subclasses, see the code for the subclass's corresponding method, and edit it there. If the class didn't have an overriding method, we could add one in the empty pane, with the method signature supplied by the browser.

This browser didn't solve all of the problems we had learning to manage a large code base spread out over many classes, but it was a huge win for dealing with the specific issue of an algorithm being distributed across several kinds of object. It also taught me two things:

  • to appreciate the level of control that Smalltalk gave developers to inspect code and shape the development experience
  • to appreciate the mindset that creating new tools is the way to mitigate many problems in software development, if not to solve them completely

The tool-making mindset is one that I came to appreciate and understand more and more as the years past. I'm disappointed whenever I don't put it to good use, but oftentimes I wise up and make the tools I need to help me do my work.


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

October 10, 2017 4:10 PM

I'm Not Correcting Someone Who Was Wrong on the Internet

Yesterday, I wrote an entire blog entry that I rm'ed before posting. I had read a decent article on a certain flavor of primitive obsession and design alternatives, which ended with what I thought was a misleading view of object-oriented programming. My blog entry set out to right this wrong.

In a rare moment of self-restraint, I resisted the urge to correct someone who was wrong on the internet. There is no sense in subjecting you to that. Instead, I'll just say that I like both OOP and functional programming, and use both regularly. I remain, in my soul, object-oriented.

On a more positive note, this morning I read an old article that made me smile, Why I'm Productive in Clojure. I don't use Clojure, but this short piece brought to mind many of the same feelings in me, but about Smalltalk. Interestingly, the sources of my feelings are similar to the author's: the right amount of syntax, facilities for meta-programming, interactive development. The article gave me a feeling that is the opposite of schadenfreude: pleasure from the pleasure of others. Some Buddhists call this mudita. I felt mudita after reading this blog entry. Rock on, Clojure dude.


Posted by Eugene Wallingford | Permalink | Categories: Personal, Software Development

September 28, 2017 3:17 PM

Pascal's Criticism of Extreme Programming

Blaise Pascal believed that the key error of the school of philosophy known as Stoicism lay in thinking that people can do always what they can, in reality, only do sometimes.

Had Pascal lived in the time of software development, he would probably have felt the same way about Extreme Programming and test-driven design.

I was reminded of Pascal the philosopher (not the language) earlier this week when I wrote code for several hours without writing my unit tests. As a result, I found myself refactoring blind for most of the project. The code was small enough that this worked out fine, and I didn't even feel much fear while moving along at a decent pace. Even so, I felt a little guilty.

Pascal made a good point about Stoicism, but I don't think that this means I ought not be a Stoic -- or a practitioner of XP. XP helps me to be a better programmer. I do have to be aware, though, that it asks me to act against my natural tendencies, just as Stoicism encourages us not to be controlled by desire or fear.

One of the beauties of XP is that it intertwines a number of practices that mutually support one another, which helps to keep me in a groove. It helps me to reduce the size of my fear, so that I don't as much to control. If I hadn't been refactoring so often this week, I probably wouldn't have even noticed that I hadn't written tests!

One need not live in fear of coming up short of the ideal. No one is perfect. I'll get back to writing my tests on my next program. There is no need to beat myself up about one program. Everything worked out fine.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

September 26, 2017 3:58 PM

Learn Exceptions Later

Yesterday, I mentioned rewriting the rules for computing FIRST and FOLLOW sets using only "plain English". As I was refactoring my descriptions, I realized that one of the reasons students have difficulty with many textbook treatments of the algorithms is that the books give complete and correct definitions of the sets upfront. The presence of X := ε rules complicates the construction of both sets, but they are unnecessary to understanding the commonsense ideas that motivate the sets. Trying to deal with ε too soon can interfere with the students learning what they need to learn in order to eventually understand ε!

When I left the ε rules out of my descriptions, I ended up with what I thought were an approachable set of rules:

  • The FIRST set of a terminal contains only the terminal itself.

  • To compute FIRST for a non-terminal X, find all of the grammar rules that have X on the lefthand side. Add to FIRST(X) all of the items in the FIRST set of the first symbol of each righthand side.

  • The FOLLOW set of the start symbol contains the end-of-stream marker.

  • To compute FOLLOW for a non-terminal X, find all of the grammar rules that have X on the righthand side. If X is followed by a symbol in the rule, add to FOLLOW(X) all of the items in the FIRST set of that symbol. If X is the last symbol in the rule, add to FOLLOW(X) all of the items in the FOLLOW set of the symbol on the rule's lefthand side.

These rules are incomplete, but they have offsetting benefits. Each of these cases is easy to grok with a simple example or two. They also account for a big chunk of the work students need to do in constructing the sets for a typical grammar. As a result, they can get some practice building sets before diving into the gnarlier details ε, which affects both of the main rules above in a couple of ways.

These seems like a two-fold application of the Concrete, Then Abstract pattern. The first is the standard form: we get to see and work with accessible concrete examples before formalizing the rules in mathematical notation. The second involves the nature of the problem itself. The rules above are the concrete manifestation of FIRST and FOLLOW sets; students can master them before considering the more abstract ε cases. The abstract cases are the ones that benefit most from using formal notation.

I think this is an example of another pattern that works well when teaching. We might call it "Learn Exceptions Later", "Handle Exceptions Later", "Save Exceptions For Later", or even "Treat Exceptions as Exceptions". (Naming things is hard.) It is often possible to learn a substantial portion of an idea without considering exceptions at all, and doing so prepares students for learning the exceptions anyway.

I guess I now have at least one idea for my next PLoP paper.

Ironically, writing this post brings to mind a programming pattern that puts exceptions up top, which I learned during the summer Smalltalk taught me OOP. Instead of writing code like this:

    if normal_case(x) then
       // a bunch
       // of lines
       // of code
       // processing x
    else
       throw_an_error
you can write:
    if abnormal_case(x) then
       throw_an_error

// a bunch // of lines // of code // processing x

This idiom brings the exceptional case to the top of the function and dispatches with it immediately. On the other hand, it also makes the normal case the main focus of the function, unindented and clear to the eye. It may look like this idiom violates the "Save Exceptions For Later" pattern, but code of this sort can be a natural outgrowth of following the pattern. First, we implement the function to do its normal business and makes sure that it handles all of the usual cases. Only then do we concern ourselves with the exceptional case, and we build it into the function with minimal disruption to the code.

This pattern has served me well over the years, far beyond Smalltalk.


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

September 25, 2017 3:01 PM

A Few Thoughts on My Compilers Course

I've been meaning to blog about my compilers course for more than a month, but life -- including my compilers course -- have kept me busy. Here are three quick notes to prime the pump.

  • I recently came across Lindsey Kuper's My First Fifteen Compilers and thought again about this unusual approach to a compiler course: one compiler a week, growing last week's compiler with a new feature or capability, until you have a complete system. Long, long-time readers of this blog may remember me writing about this idea once over a decade ago.

    The approach still intrigues me. Kuper says that it was "hugely motivating" to have a working compiler at the end of each week. In the end I always shy away from the approach because (1) I'm not yet willing to adopt for my course the Scheme-enabled micro-transformation model for building a compiler and (2) I haven't figured out how to make it work for a more traditional compiler.

    I'm sure I'll remain intrigued and consider it again in the future. Your suggestions are welcome!

  • Last week, I mentioned on Twitter that I was trying to explain how to compute FIRST and FOLLOW sets using only "plain English". It was hard. Writing a textual description of the process made me appreciate the value of using and understanding mathematical notation. It is so expressive and so concise. The problem for students is that it is also quite imposing until they get it. Before then, the notation can be a roadblock on the way to understanding something at an intuitive level.

    My usual approach in class to FIRST and FOLLOW sets, as for most topics, is to start with an example, reason about it in commonsense terms, and only then to formalize. The commonsense reasoning often helps students understand the formal expression, thus removing some of its bite. It's a variant of the "Concrete, Then Abstract" pattern.

    Mathematical definitions such as these can motivate some students to develop their formal reasoning skills. Many people prefer to let students develop their "mathematical maturity" in math courses, but this is really just an avoidance mechanism. "Let the Math department fail them" may solve a practical problem, sometimes we CS profs have to bite the bullet and help our students get better when they need it.

  • I have been trying to write more code for the course this semester, both for my enjoyment (and sanity) and for use in class. Earlier, I wrote a couple of toy programs such as a Fizzbuzz compiler. This weekend I took a deeper dive and began to implement my students' compiler project in full detail. It was a lot of fun to be deep in the mire of a real program again. I have already learned and re-learned a few things about Python, git, and bash, and I'm only a quarter of the way in! Now I just have to make time to do the rest as the semester moves forward.

In her post, Kuper said that her first compiler course was "a lot of hard work" but "the most fun I'd ever had writing code". I always tell my students that this course will be just like that for them. They are more likely to believe the first claim than the second. Diving in, I'm remembering those feelings firsthand. I think my students will be glad that I dove in. I'm reliving some of the challenges of doing everything that I ask them to do. This is already generating a new source of empathy for my students, which will probably be good for them come grading time.


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

August 11, 2017 9:08 AM

Don't Say "Straightforward" So Often, Obviously

This bullet point from @jessitron's Hyperproductive Development really connected with me:

As the host symbiont who lives and breathes the system: strike the words "just", "easy", "obvious", "simple", and "straightforward" from your vocabulary. These words are contextual, and no other human shares your context.

My first experience coming to grips with my use of these words was not in software development, but in the classroom. "Obvious" has never been a big part of my vocabulary, but I started to notice a few years ago how often I said "just", "easy", and "simple" in class and wrote them in my lecture notes. Since then, I have worked hard to cut back sharply on my uses of these minimizers in both spoken and written interactions with my students. I am not always successful, of course, but I am more aware now and frequently catch myself before speaking, or in the act of writing.

I find that I still use "straightforward" quite often these days. Often, I use it to express contrast explicitly, something to the effect, "This won't necessarily be easy, but at least it's straightforward." By this I mean that some problem or task may require hard work, but at least the steps they need to perform should be clear. I wonder now, though, whether students always take it this way, even when expressed explicitly. Maybe they hear me minimizing the task head, not putting the challenge they face into context.

Used habitually, even with good intentions, a word like "straightforward" can become a crutch, a substitute minimizer. It lets me to be lazy when I try to summarize a process or to encourage students when things get difficult. I'm going to try this fall to be more sensitive to my use of "straightforward" and see if I can't find a better way in most situations.

As for the blog post that prompted this reflection, Hyperproductive Development summarizes as effectively as anything I've read the truth behind the idea that some programmers are so much more effective than others: "it isn't the developers, so much as the situation". It's a good piece, well worth a quick read.


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

July 28, 2017 2:02 PM

The Need for Apprenticeship in Software Engineering Education

In his conversation with Tyler Cowen, Ben Sasse talks a bit about how students learn in our schools of public policy, business, and law:

We haven't figured out in most professional schools how to create apprenticeship models where you cycle through different aspects of what doing this kind of work will actually look like. There are ways that there are tighter feedback loops at a med school than there are going to be at a policy school. There are things that I don't think we've thought nearly enough about ways that professional school models should diverge from traditional, theoretical, academic disciplines or humanities, for example.

We see a similar continuum in what works best, and what is needed, for learning computer science and learning software engineering. Computer science education can benefit from the tighter feedback loops and such that apprenticeship provides, but it also has a substantial theoretical component that is suitable for classroom instruction. Learning to be a software engineer requires a shift to the other end of the continuum: we can learn important things, in the classroom, but much of the important the learning happens in the trenches, making things and getting feedback.

A few universities have made big moves in how they structure software engineering instruction, but most have taken only halting steps. They are often held back by a institutional loyalty to the traditional academic model, or out of sheer curricular habit.

The one place you see apprenticeship models in CS is, of course, graduate school. Students who enter research work in the lab under the mentorship of faculty advisors and more senior grad students. It took me a year or so in graduate school to figure out that I needed to begin to place more focus on my research ideas than on my classes. (I hadn't committed to a lab or an advisor yet.)

In lieu of a changed academic model, internships of the sort I mentioned recently can be really helpful for undergrad CS students looking to go into software development. Internships create a weird tension for faculty... Most students come back from the workplace with a new appreciation for the academic knowledge they learn in the classroom, which is good, but they also back to wonder why more of their schoolwork can't have the character of learning in the trenches. They know to want more!

Project-based courses are a way for us to bring the value of apprenticeship to the undergraduate classroom. I am looking forward to building compilers with ten hardy students this fall.


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

July 21, 2017 3:47 PM

Some Thoughts from a Corporate Visit: Agility and Curriculum

Last Thursday, I spent a day visiting a major IT employer in our state. Their summer interns, at least three of whom are students in my department, were presenting projects they had developed during a three-day codejam. The company invited educators from local universities to come in for the presentations, preceded by a tour of the corporate campus, a meeting with devs who had gone through the internship program in recent years, and a conversation about how the schools and company might collaborate more effectively. Here are a few of my impressions from the visit.

I saw and heard the word "agile" everywhere. The biggest effects of the agility company-wide seemed to be in setting priorities and in providing transparency. The vocabulary consisted mostly of terms from Scrum and kanban. I started to wonder how much the programming practices of XP or other agile methodologies had affected software development practices there. Eventually I heard about the importance of pair programming and unit testing and was happy to know that the developers hadn't been forgotten in the move to agile methods.

Several ideas came to mind during the visit of things we might incorporate into our programs or emphasize more. We do a pretty good job right now, I think. We currently introduce students to agile development extensively in our software engineering course, and we have a dedicated course on software verification and validation. I have even taught a dedicated course on agile software development several times before, most recently in 2014 and 2010. Things we might do better include:

  • having students work on virtual teams. Our students rarely, if ever, work on virtual teams in class, yet this is standard operating procedure even within individual companies these days.

  • having students connect their applications programs to front and back ends. Our students often solve interesting problems with programs, but they don't always have to connect their solution to front ends that engage real users or to back ends that ultimately provide source data. There is a lot to learn in having to address these details.

  • encouraging students to be more comfortable with failure on projects. Schools tends to produce graduates who are risk-averse, because failure on a project in the context of a semester-long course might mean failure in the course. But the simple fact is that some projects fail. Graduates need to be able to learn from failure and create successes out of it. They also need to be willing to take risks; projects with risk are also where big wins come from, not to mention new knowledge.

Over the course of the day, I heard about many of the attributes this company likes to see in candidates for internships and full-time positions, among them:

  • comfort speaking in public
  • ability to handle, accept, and learn from failure
  • curiosity
  • initiative
  • a willingness to work in a wide variety of roles: development, testing, management, etc.
Curiosity was easily the most-mentioned desirable attribute. On the matter of working in a wide variety of roles, even the people with "developer" in their job title reported spending only 30% of their time writing code. One sharp programmer said, "If you're spending 50% of your time writing code, you're doing something wrong."

The codejam presentations themselves were quite impressive. Teams of three to six college students can do some amazing things in three days when they are engaged and when they have the right tools available to them. One theme of the codejam was "platform as a service", and students used a slew of platforms, tools, and libraries to build their apps. Ones that stood out because they were new to me included IBM BlueMix (a l´ AWS and Azure), Twilio ("a cloud platform for building SMS, voice and messaging apps"), and Flask ("a micro web framework written in Python"). I also saw a lot of node.js and lots and lots of NoSQL. There was perhaps a bias toward NoSQL in the tools that the interns wanted to learn, but I wonder if students are losing appreciation for relational DBs and their value.

Each team gave itself a name. This was probably my favorite:

   int erns;
I am a programmer.

All in tools, the interns used too many different tools for me to take note of. That was an important reminder from the day for me. There are so many technologies to learn and know how to use effectively. Our courses can't possibly include them all. We need to help students learn how to approach a new library or framework and become effective users as quickly as possible. And we need to have them using source control all the time, as ingrained habit.

One last note, if only because it made me smile. Our conversation with some of the company's developers was really interesting. At the end of the session, one of the devs handed out his business card, in case we ever wanted to ask him questions after leaving. I looked down at the card and saw...

Alan Kay's business card, redacted

... Alan Kay. Who knew that Alan was moonlighting as an application developer for a major financial services company in the Midwest? I'm not sure whether sharing a name with a titan of computer science is a blessing or a curse, but for the first time in a long while I enjoyed tucking a business card into my pocket.


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

July 17, 2017 2:35 PM

Getting Started With Unit Testing

Someone wrote on the Software Carpentry mailing list:

I'm using Python's unittest framework and everything is already set up. The specific problem I need help with is what tests to write...

That is, indeed, a problem. I have the tool. What now?

Rather than snark off-line, like me, Titus Brown wrote a helpful answer with generic advice for how to get started writing tests for code that is already written, aimed at scientists relatively new to software development. It boils down to four suggestions:

  • Write "smoke" tests that determine whether the program works as intended.
  • Write a series of basic tests for edge cases.
  • As you add new code to the program, write tests for it at the same time.
  • "Whenever you discover a bug, write a test against that bug before fixing it."

Brown says that the smoke tests "should be as dumb and robust as possible". They deliver a lot of value for the little effort. I would add that they also get you in the rhythm of writing tests without a huge amount of thought necessary. That rhythm is most helpful as you start to tackle the tougher cases.

Brown calls his last bullet "stupidity driven testing", which is a self-deprecating way to describe a locality phenomenon that many of us have observed in our programs: code in which we've found errors is often likely to contain other errors. Adding tests to this part of the program helps the test suite to evolve to protect a potentially weak part of the codebase.

He also recommends a simple practice for the third bullet that I have found helpful for both bullets three and four: When you write these tests, try to cover some of the existing, working functionality, too. Whenever I add a new test to the growing test base, I try to add one or two more tests not called for by the new code or the bug I'm fixing. I realize that this may distract a bit from the task at hand, but it's a low-cost way to grow the test suite without setting aside dedicated time. I try to keep these add-on tests reasonably close to the part of the program I'm adding or fixing. This allows me to benefit from the thinking I'm already doing about that part of the program.

At some point, it's good to take a look at code coverage to see if there are parts of the code that con't yet have tests written for them. Those parts of the program can be the focus of dedicated test-writing sessions as time permits.

Brown also gives a piece of advice that seasoned developers should already know: make the tests part of continuous integration. They should run every time we update the application. This keeps us honest and our code clean.

All in all, this is pretty good advice. That's not surprising. I usually learn something from Brown's writing.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

June 29, 2017 4:03 PM

A New Demo Compiler for My Course

a simple FizzBuzz program

Over the last couple of weeks, I have spent a few minutes most afternoons writing a little code. It's been the best part of my work day. The project was a little compiler.

One of the first things we do in my compiler course is to study a small compiler for a couple of the days. This is a nice way to introduce the stages of a compiler and to raise some of the questions that we'll be answering over the course of the semester. It also gives students a chance to see the insides of a working compiler before they write their own. I hope that this demystifies the process a little: "Hey, a compiler really is just a program. Maybe I can write one myself."

For the last decade or so, I have used a compiler called acdc for this demo, based on Chapter 2 of Crafting A Compiler by Fischer, Cytron, and LeBlanc. ac is a small arithmetic language with two types of numbers, sequences of assignment statements, and print statements. dc is a stack-based desk calculator that comes as part of many Unix installations. I whipped up a acdc compiler in Java about a decade ago and have used it ever since. Both languages have enough features to be useful as a demo but not enough to overwhelm. My hacked-up compiler is also open to improvements as we learn techniques throughout the course, giving us a chance to use them in the small before students applied them to their own project.

I've been growing dissatisfied with this demo for a while now. My Java program feels heavy, with too many small pieces to be simple enough for a quick read. It requires two full class sessions to really understand it well, and I've been hoping to shorten the intro to my course. ac is good, but it doesn't have any flow control other than sequencing, which means that it does not give us a way to look at assembly language generation with jumps and backpatching. On top of all that, I was bored with acdc; ten years is a long time to spend with one program.

This spring I stumbled on a possible replacement in The Fastest FizzBuzz in the West. It defines a simple source language for writing FizzBuzz programs declaratively. For example:

   1...150
   fizz=3
   buzz=5
   woof=7
produces the output of a much larger program in other languages. Imagine being able to pull this language during your next interview for a software dev position!

This language is really simple, which means that a compiler for it can be written in relatively few lines of code. However, it also requires generating code with a loop and if-statements, which requires thinking about branching patterns in assembly language.

The "Fastest FizzBuzz" article uses a Python parser generator to create its compiler. For my course, I want something that my students can read with only their knowledge coming into the course, and I want the program to be transparent enough so that they can see directly how each stage works and how it interacts with other parts of the compiler.

I was also itching to write a program, so I did.

I wrote my compiler in Python. It performs a simple scan of the source program, taking as much advantage of the small set of simple tokens as possible. The parser works by recursive descent, which also takes advantage of the language's simple structure. The type checker makes sure the numbers all make sense and that the words are unique. Finally, to make things even simpler, the code generator produces an executable Python 3.4 program.

I'm quite hopeful about this compiler's use as a class demo. It is simple enough to read in one sitting, even by students who enter the course with weaker programming skills. Even so, the language can also be used to demonstrate the more sophisticated techniques we learn throughout the course. Consider:

  • Adding comments to the source language overwhelms the ad hoc approach I use in the scanner, motivating the use of a state machine.
  • While the parser is easily handled by recursive descent, the language is quite amenable to a simple table-driven approach, too. The table-driven parser will be simple enough that students can get the hang of the technique with few unnecessary details.
  • The type checker demonstrates walking an abstract syntax tree without worrying about too many type rules. We can focus our attention on type systems when dealing with the more interesting source language of their project.
  • The code generator has to deal with flow of control, which enables us to learn assembly language generation on a smaller scale without fully implementing code to handle function calls.
So this compiler can be a demo in the first week of the course and also serve as a running example throughout.

We'll see how well this plays in class in a couple of months. In any case, I had great fun ending my days the last two weeks by firing up emacs or IDLE and writing code. As a bonus, I used this exercise to improve my git skills, taking them beyond the small set of commands I have used on my academic projects in the past. (git rebase -i is almost my friend now.) I also wrote more pyunit tests than I have written in a long, long time, which reminded me of some of the challenges students face when trying to test their code. That should serve me well in the fall, too.

I do like writing code.


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

June 23, 2017 2:04 PM

No Summer Job? Learn How to Program

The article Why Aren't American Teenagers Working Anymore? comments on a general trend I have observed locally over the last few years: most high school students don't have summer jobs any more. At first, you might think that rising college tuition would provide an incentive to work, but the effect is almost the opposite:

"Teen earnings are low and pay little toward the costs of college," the BLS noted this year. The federal minimum wage is $7.25 an hour. Elite private universities charge tuition of more than $50,000.

Even in-state tuition at a public universities has grown large enough to put it out of the reach of the typical summer jobs. Eventually, there is almost no point in working a low-paying job; you'll have to borrow significant amount anyway.

These days, students have another alternative that might pay off better in the long run anyway. With a little gumption and free resources available on the web, many students can learn to program, build websites, and make mobile apps. Time spent not working a job but developing skills that are in high demand and which pay well might be time spent well.

Even as a computer scientist, though, I'm traditional enough to be a little uneasy with this idea. Don't young people benefit from summer jobs in ways other than a paycheck? The authors of this article offer the conventional thinking:

A summer job can help teenagers grow up as it expands their experience beyond school and home. Working teens learn how to manage money, deal with bosses, and get along with co-workers of all ages.

You know what, though... A student working on an open-source project can learn also how to deal with people in positions of relative authority and learn how to get along with collaborators of all ages. They might even get to interact with people from other cultures and make a lasting contribution to something important.

Maybe instead of worrying about teenagers getting summer jobs we should introduce them to programming and open-source software.


Posted by Eugene Wallingford | Permalink | Categories: General, Software Development

June 06, 2017 2:39 PM

Using Programs and Data Analysis to Improve Writing, World Bank Edition

Last week I read a tweet that linked to an article by Paul Romer. He is an economist currently working at the World Bank, on leave from his chair at NYU. Romer writes well, so I found myself digging deeper and reading a couple of his blog articles. One of them, Writing, struck a chord with me both as a writer and as a computer scientist.

Consider:

The quality of written prose should be higher in documents that will have many readers.

This is true of code, too. If a piece of code will be read many times, whether by one person or several, then each minute spent making it shorter and clearer improves reading comprehension every single time. That's even more important in code than in text, because so often we read code in order to change it. We need to understand it at even deeper level to ensure that our changes have the intended effect. Time spent making code better repays itself many times over.

Romer caused a bit of a ruckus when he arrived at the World Bank by insisting, to some of his colleagues' displeasure, that everyone in his division writer clearer, more concise reports. His goal was admirable: He wanted more people to be able to read and understand these reports, because they deal with policies that matter to the public.

He also wanted people to trust what the World Bank was saying by being able more readily to see that a claim was true or false. His article looks at two different examples that make a claim about the relationship between education spending and GDP per capita. He concludes his analysis of the examples with:

In short, no one can say that the author of the second claim wrote something that is false because no one knows what the second claim means.

In science, writing clearly builds trust. This trust is essential for communicating results to the public, of course, because members of the public do not generally possess the scientific knowledge they need to assess the truth of claim directly. But it is also essential for communicating results to other scientists, who must understand the claims at a deeper level in order to support, falsify, and extend them.

In the second half of the article, Romer links to a study of the language used in World Bank's yearly reports. It looks at patterns such as the frequency of the word "and" in the reports and the ratio of nouns to verbs. (See this Financial Times article for a fun little counterargument on the use of "and".)

Romer wants this sort of analysis to be easier to do, so that it can be used more easily to check and improve the World Bank's reports. After looking at some other patterns of possible interest, he closes with this:

To experiment with something like this, researchers in the Bank should be able to spin up a server in the cloud, download some open-source software and start experimenting, all within minutes.

Wonderful: a call for storing data in easy-to-access forms and a call for using (and writing) programs to analyze text, all in the name not of advancing economics technically but of improving its ability to communicate its results. Computing becomes a tool integrated into the process of the World Bank doing its designated job. We need more leaders in more disciplines thinking this way. Fortunately, we hear reports of such folks more often these days.

Alas, data and programs were not used in this way when Romer arrived at the World Bank:

When I arrived, this was not possible because people in ITS did not trust people from DEC and, reading between the lines, were tired of dismissive arrogance that people from DEC displayed.

One way to create more trust is to communicate better. Not being dismissively arrogant is, too, though calling that sort of behavior out may be what got Romer in so much hot water with the administrators and economists at the World Bank in the first place.


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

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 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

April 28, 2017 11:27 AM

Data Compression and the Complexity of Consciousness

Okay, so this is cool:

Neuroscientists stimulate the brain with brief pulses of energy and then record the echoes that bounce back. Dreamless sleep and general anaesthesia return simple echoes; brains in conscious states produce more complex patterns. Then comes a little inspiration from data compression:

Excitingly, we can now quantify the complexity of these echoes by working out how compressible they are, similar to how simple algorithms compress digital photos into JPEG files. The ability to do this represents a first step towards a "consciousness-meter" that is both practically useful and theoretically motivated.

This made me think of Chris Ford's StrangeLoop 2015 talk about using compression to understand music. Using compressibility as a proxy for complexity gives us a first opportunity to understand all sorts of phenomena about which we are collecting data. Kolmogorov complexity is a fun tool for programmers to wield.

The passage above is from an Aeon article on the study of consciousness. I found it an interesting read from beginning to end.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Patterns, Software Development

April 07, 2017 1:33 PM

Two Very Different Kinds of Student

The last sentence of each of these passages reminds me of some of the students over the years.

First this, from Paul Callaghan's The Word Chain Kata:

One common way to split problems is via the "generate and test" pattern, where one component suggests results and the other one discards invalid ones. (In my experience, undergrad programmers are experts in this pattern, although they tend to use it as a [software development] methodology--but that's another story.)

When some students learn to program for the first time, they start out by producing code that looks like something they have seen before, trying it out, and then tinkering with it until it works or until they become exasperated. (I always hope that they act on their exasperation by asking me for help, rather than by giving up.) These students usually understand little bits of the code locally, but they don't really understand the program or function as a whole. Yet, somehow, they find a way to make it work.

It's surprising how far some students can get in a course of study by programming this way. (That's why Callaghan calling the approach a methodology made me smile.) It's unfortunate, too, because eventually the approach hits a wall when problems and domains become more challenging. Or when they run into a course where they program in Racket, in which one misplaced parenthesis can cause an otherwise perfect piece of code to implode. Lisp-like languages do not provide a supportive environment for this kind of "programming by wandering around".

And then there's this, from Andy Hertzfeld's fun little story about the writing of the classic manual Inside Macintosh:

Pretty soon, I figured out that if Caroline had trouble understanding something, it probably meant that the design was flawed. On a number of occasions, I told her to come back tomorrow after she asked a penetrating question, and revised the API to fix the flaw that she had pointed out. I began to imagine her questions when I was coding something new, which made me work harder to get things clearer before I went over them with her.

In this story, Caroline is not a student, but a young new writer assigned to the Mac documentation team. Still, she reminds me of students who are as delightful to work with as generate-and-test programmers can be frustrating. These students pay attention. They ask good questions, ones that often challenge the unstated assumptions underlying what we have explained before. At first, this can seem frustrating to us teachers, because we have to formulate answers for things that should be obvious. But that's the point: they aren't obvious, at least not to everyone, and us thinking they are obvious is inhibiting our teaching.

Last semester, I had one team of students in my compilers class that embodied this attitude. They asked questions no one had ever bothered to ask me before. At first, I thought, "How can these guys not understand such basic material?" Like Hertzfeld, though, pretty soon I figured out that their questions were exposing holes or weaknesses in my lectures, examples, and sample code. I began to anticipate their questions as I prepared for class. Their questions helped me see ways to make my course better.

As along so many other dimensions, part of the challenge in teaching CS is the wide variation in the way students study, learn, and approach their courses. It is also a part of the great fun of teaching, especially when you encounter the Carolines and Averys who push me to get better.


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

April 02, 2017 12:02 PM

Reading an Interview with John McPhee Again, for the First Time

"This weekend I enjoyed Peter Hessler's interview of McPhee in The Paris Review, John McPhee, The Art of Nonfiction No. 3."

That's a direct quote from this blog. Don't remember it? I don't blame you; neither do I. I do remember blogging about McPhee back when, but as I read the same Paris Review piece again last Sunday and this, I had no recollection of reading it before, no sense of déjà vu at all.

Sometimes having a memory like mine is a blessing: I occasionally get to read something for the first time again. If you read my blog, then you get to read my first impressions for a second time.

I like this story that McPhee told about Bob Bingham, his editor at The New Yorker:

Bingham had been a writer-reporter at The Reporter magazine. So he comes to work at The New Yorker, to be a fact editor. Within the first two years there, he goes out to lunch with his old high-school friend Gore Vidal. And Gore says, What are you doing as an editor, Bobby? What happened to Bob Bingham the writer? And Bingham says, Well, I decided that I would rather be a first-rate editor than a second-rate writer. And Gore Vidal draws himself up and says, And what is wrong with a second-rate writer?

I can just hear the faux indignation in Vidal's voice.

McPhee talked a bit about his struggle over several years to write a series of books on geology, which had grown out of an idea for a one-shot "Talk of the Town" entry. The interviewer asked him if he ever thought about abandoning the topic and moving on to something he might enjoy more. McPhee said:

The funny thing is that you get to a certain point and you can't quit. Because I always worried: if you quit, you'll quit again. The only way out was to go forward, to learn your way and write your way out of it.

I know that feeling. Sometimes, I really do need to quit something and move on, but I always wonder whether quitting this time will make it easier to do next time. Because sometimes, I need to stick it out and, as McPhee says, learn my way out of the difficulty. I have no easy answers for knowing when quitting is the right thing to do.

Toward the end of the interview, the conversation turned to the course McPhee teaches at Princeton, once called "the literature of fact". The university first asked him to teach on short notice, over the Christmas break in 1974, and he accepted immediately. Not everyone thought it was a good idea:

One of my dear friends, an English teacher at Deerfield, told me: Do not do this. He said, Teachers are a dime a dozen -- writers aren't. But my guess is that I've been more productive as a writer since I started teaching than I would have been if I hadn't taught. In the overall crop rotation, it's a complementary job: I'm looking at other people's writing, and the pressure's not on me to do it myself. But then I go back quite fresh.

I know a lot of academics who feel this way. Then again, it's a lot easier to stay fresh in one's creative work if one has McPhee's teaching schedule, rather than a full load of courses:

My schedule is that I teach six months out of thirty-six, and good Lord, that leaves a lot of time for writing, right?

Indeed it does. Indeed it does.

On this reading of the interview, I marked only two passages that I wrote about last time. One came soon after the above response, on how interacting with students is its own reward. The other was a great line about the difference between mastering technique and having something to say: You demonstrated you know how to saddle a horse. Now go find the horse.

That said, I unconsciously channeled this line from McPhee just yesterday:

Writing teaches writing.

We had a recruitment event on campus, and I was meeting with a dozen or so prospective students and their entourages. We were talking about our curriculum, and I said a few words about our senior project courses. Students generally like these courses, even though they find them difficult. The students have never had to write a big program over the course of several months, and it's harder than it looks. The people who hire our graduates like these courses, too, because they know that these courses are places where students really begin to learn to program.

In the course of my remarks, I said something to the effect, "You can learn a lot about programming in classes where you study languages and techniques and theory, but ultimately you learn to write software by writing software. That's what the project courses are all about." There were a couple of experienced programmers in the audience, and they were all nodding their heads. They know McPhee is right.


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

March 22, 2017 4:50 PM

Part of the Fun of Programming

As I got ready for class yesterday morning, I decided to refactor a piece of code. No big deal, right? It turned out to be a bigger deal than I expected. That's part of the fun of programming.

The function in question is a lexical addresser for a little language we use as a specimen in my Programming Languages course. My students had been working on a design, and it was time for us to build a solution as a group. Looking at my code from the previous semester, I thought that changing the order of two cases would make for a better story in class. The cases are independent, so I swapped them and ran my tests.

The change broke my code. It turns out that the old "else" clause had been serving as a convenient catch-all and was only working correctly due to an error in another function. Swapping the cases exposed the error.

Ordinarily, this wouldn't be a big deal, either. I would simply fix the code and give my students a correct solution. Unfortunately, I had less than an hour before class, so I now found myself in a scramble to find the bug, fix it, and make the changes to my lecture notes that had motivated the refactor in the first place. Making changes like this under time pressure is rarely a good idea... I was tempted to revert to the previous version, teach class, and make the change after class. But I am a programmer, dogged and often foolhardy, so I pressed on. With a few minutes to spare, I closed the editor on my lecture notes and synced the files to my teaching machine. I was tired and still had a little nervous energy coursing through me, but I felt great. That's part of the fun of programming.

I will say this: Boy, was I glad to have my test suite! It was incomplete, of course, because I found an error in my program. But the tests I did have helped me to know that my bug fix had not broken something else unexpectedly. The error I found led to several new tests that make the test suite stronger.

This experience was fresh in my mind this morning when I read "Physics Was Paradise", an interview with Melissa Franklin, a distinguished experimental particle physicist at Harvard. At one point, Franklin mentioned taking her first physics course in high school. The interviewer asked if physics immediately stood out as something she would dedicate her life to. Franklin responded:

Physics is interesting, but it didn't all of a sudden grab me because introductory physics doesn't automatically grab people. At that time, I was still interested in being a writer or a philosopher.

I took my first programming class in high school and, while I liked it very much, it did not cause me to change my longstanding intention to major in architecture. After starting in the architecture program, I began to sense that, while I liked architecture and had much to learn from it, computer science was where my future lay. Maybe somewhere deep in my mind was memory of an experience like the one I had yesterday, battling a piece of code and coming out with a sense of accomplishment and a desire to do battle again. I didn't feel the same way when working on problems in my architecture courses.

Intro CS, like intro physics, doesn't always snatch people away from their goals and dreams. But if you enjoy the fun of programming, eventually it sneaks up on you.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Personal, Software Development

March 16, 2017 8:50 AM

Studying Code Is More Like Natural Science Than Reading

A key passage from Peter Seibel's 2014 essay, Code Is Not Literature:

But then it hit me. Code is not literature and we are not readers. Rather, interesting pieces of code are specimens and we are naturalists. So instead of trying to pick out a piece of code and reading it and then discussing it like a bunch of Comp Lit. grad students, I think a better model is for one of us to play the role of a 19th century naturalist returning from a trip to some exotic island to present to the local scientific society a discussion of the crazy beetles they found: "Look at the antenna on this monster! They look incredibly ungainly but the male of the species can use these to kill small frogs in whose carcass the females lay their eggs."

The point of such a presentation is to take a piece of code that the presenter has understood deeply and for them to help the audience understand the core ideas by pointing them out amidst the layers of evolutionary detritus (a.k.a. kludges) that are also part of almost all code. One reasonable approach might be to show the real code and then to show a stripped down reimplementation of just the key bits, kind of like a biologist staining a specimen to make various features easier to discern.

My scientist friends often like to joke that CS isn't science, even as they admire the work that computer scientists and programmers do. I think Seibel's essay expresses nicely one way in which studying software really is like what natural scientists do. True, programs are created by people; they don't exist in the world as we find it. (At least programs in the sense of code written by humans to run on a computer.) But they are created under conditions that look a lot more like biological evolution than, say, civil engineering.

As Hal Abelson says in the essay, most real programs end up containing a lot of stuff just to make it work in the complex environments in which they operate. The extraneous stuff enables the program to connect to external APIs and plug into existing frameworks and function properly in various settings. But the extraneous stuff is not the core idea of the program.

When we study code, we have to slash our way through the brush to find this core. When dealing with complex programs, this is not easy. The evidence of adaptation and accretion obscures everything we see. Many people do what Seibel does when they approach a new, hairy piece of code: they refactor it, decoding the meaning of the program and re-coding it in a structure that communicates their understanding in terms that express how they understand it. Who knows; the original program may well have looked like this simple core once, before it evolved strange appendages in order to adapt to the condition in which it needed to live.

The folks who helped to build the software patterns community recognized this. They accepted that every big program "in the wild" is complex and full of cruft. But they also asserted that we can study such programs and identify the recurring structures that enable complex software both to function as intended and to be open to change and growth at the hands of programmers.

One of the holy grails of software engineering is to find a way to express the core of a system in a clear way, segregating the extraneous stuff into modules that capture the key roles that each piece of cruft plays. Alas, our programs usually end up more like the human body: a mass of kludges that intertwine to do some very cool stuff just well enough to succeed in a harsh world.

And so: when we read code, we really do need to bring the mindset and skills of a scientist to our task. It's not like reading People magazine.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Patterns, Software Development

March 05, 2017 10:53 AM

"Flying by Instruments" and Learning a New Programming Style

Yesterday afternoon I listened to a story told by someone who had recently been a passenger in a small plane flown by a colleague. As they climbed to their cruising altitude, which was clear and beautiful, the plane passed through a couple thousand feet of heavy clouds. The pilot flew confidently, having both training and experience in instrument flight.

The passenger telling the story, however, was disoriented and a little scared by being in the clouds and not knowing where they were heading. The pilot kept him calm by explaining the process of "flying by instruments" and how he had learned it. Sometimes, learning something new can give us confidence. Other times, just listening to a story can distract us enough to get us through a period of fear.

This story reminded me of a session early in my programming languages course, when students are learning Racket and functional programming style. Racket is quite different from any other language they have learned. "Don't dip your toes in the water," I tell them. "Get wet."

For students who prefer their learning analogies not to involve potential drowning -- that is, after all, the sensation many of them report feeling as they learn to cope with all of Racket's parentheses for the first time -- I relate an Alan Kay story that talks about learning to fly an airplanes after already knowing how to drive a car. Imagine what the world be like if everyone refused to learn how to fly a plane because driving was so much more comfortable and didn't force them to bend their minds a bit? Sure, cars are great and serve us well, but planes completely change the world by bringing us all closer together.

I have lost track of where I had heard or read Kay telling that story, so when I wrote up the class notes, I went looking for a URL to cite. I never found one, but while searching I ran across a different use of airplanes in an analogy that I have since worked into my class. Here's the paragraph I use in my class notes, the paragraph I thought of while listening to the flying-by-instruments story yesterday:

The truth is that bicycles and motorcycles operate quite differently than wheeled vehicles that keep three or more wheels on the ground. For one thing, you steer by leaning, not with the handlebars or steering wheel. Learning to fly an airplane gives even stronger examples of having to learn that your instincts are wrong, and that you have to train yourself to "instinctively" know not only that you turn by banking rather than with the rudder, but that you control altitude primarily with the throttle, not the elevators, speed primarily with the elevators not the throttle, and so forth.

Learning to program in a new style, whether object-oriented, functional, or concatenative, usually requires us to overcome deeply-ingrained design instincts and to develop new instincts that feel uncomfortable while we are learning. Developing new instincts takes some getting used to, but it's worth the effort, even if we choose not to program much in the new style after we learn it.

Now I find myself thinking about what it means to "fly by instruments" when we program. Is our unit testing framework one of the instruments we come to rely on? What about a code smell detector such as Reek? If you have thoughts on this idea, or pointers to what others have already written, I would love to hear from you.

Postscript.   I originally found the passage quoted above in a long-ish article about Ruby and Smalltalk, but that link has been dead for a while. I see that the article was reposted in a Ruby Buzz Forum message called On Ceremony and Training Wheels.

Oh, and if you know where I can find the Alan Kay story I went looking for online, I will greatly appreciate any pointers you can offer!


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

February 28, 2017 3:47 PM

Comments on Comments

Over the last couple of days, a thread on the SIGCSE mailing list has been revisiting the well-tilled ground of comments in code. As I told my students at the beginning of class this semester, some of my colleagues consider me a heretic for not preaching the Gospel of Comments in Code. Every context seems to have its own need for, and expectations of, comments. Wherever students end up working, both while in school and after graduation, their employers will set a standard and expect them to follow. They will figure it out.

In most of my courses, I define a few minimal standard, try to set a good example in the code I give my students, and otherwise don't worry much about comments. Part of my example is that different files I give them are commented differently, depending on the context. A demo of an idea, a library to be reused in the course, and an application are different enough that they call for different kinds of comments. In a course such as compiler development, I require more documentation, both in and out of the code. Students live with that code for a semester and come to value some of their own comments many weeks later.

Anyway, the SIGCSE thread included two ideas that I liked, though they came from competing sides of the argument. One asserted that comments are harmful, because:

They're something the human reader can see but the computer can't, and therefore are a source of misunderstanding.

I love the idea of thinking in terms of misunderstandings between humans and the computer.

The other responded to another poster's suggestion that students be encouraged to write comments with themselves in mind: What would you like to know if you open this code six months from now? The respondent pointed out that this is unreasonable: Answering that question requires...

... a skill that is at least on par with good programming skills. Certainly new CS students are unable to make this kind of decision.

The thread has been a lot of fun to read. I remain mostly of the view that:

  • It's better to write code that says what it means and thus needs as few comments as possible. This is a skill students can and should work on all the time time.

  • If the code is likely to conflict with the expectations of the people most likely to read your code, then add a comment. This part depends a lot on context and experience. Students are just now earning their experience, and the context in which they work changes from course to course and job to job.
Students who care about programming, or who come to care about it over time, will care (or come to care) about comments, too.


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

February 23, 2017 4:08 PM

Surrounding Yourself with Beginners

This comment at the close of a recent Dan Meyer post struck close to home:

I haven't found a way to generate these kinds of insights about math without surrounding myself with people learning math for the first time.

I've learned a lot about programming from teaching college students. Insights can come at all levels, from working with seniors who are writing compilers as their first big project, through midstream students who are learning OOP or functional programming as a second or third style, right down to beginners who are seeing variables and loops and functions for the first time.

Sometimes an insight comes when a student asks a new question, or an old question at the right time. I had a couple of students in my compiler course last fall who occasionally asked the most basic questions, especially about code generation. Listening to their questions and creating new examples to illustrate my answers helped me think differently about the run-time system.

Other times, they come while listening to students talk among themselves. One student's answer to another student's question can trigger an entirely new way for me to think about a concept I think I understand pretty well. I don't have any recent personal examples in mind, but this sort of experience seems to be part of what triggered Meyer's post.

People are always telling us to "be the least experienced person in the room", to surround ourselves with "smarter" or more experienced people and learn from them. But there is a lot to be learned from programmers who are just starting out. College profs have that opportunity all the time, if they are willing to listen and learn.


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

February 12, 2017 11:11 AM

Howard Marks on Investing -- and Software Development

Howard Marks is an investor and co-founder of Oaktree Capital Management. He has a big following in the financial community for his views on markets and investing, which often stray from orthodoxy, and for his straightforward writing and speaking style. He's a lot like Warren Buffett, with less public notoriety.

This week I read Marks's latest memo [ PDF ] to Oak Tree's investors, which focuses on expert opinion and forecasting. This memo made me think a lot about software development. Whenever Marks talks about experts predicting how the market would change and how investors should act, I thought of programming. His comments sound like the wisdom of an agile software developer.

Consider what he learned from the events of 2016:

  1. First, no one really knows what events are going to transpire.
  2. And second, no one knows what the market's reaction to those events will be.

Investors who got out of the market for the last couple of months of 2016, based on predictions about what would happen, missed a great run-up in value.

If a programmer cannot predict what will happen in the future, or how stakeholders will respond to these changes, then planning in too much detail is at best an inefficient use of time and energy. At worst it is a way to lock yourself into code that you really need to change but can't.

Or consider these thoughts on surprises (the emphasis in the original):

It's the surprises no one can anticipate that would move markets most if they were to happen. But (a) most people can't imagine them and (b) most of the time they don't happen. That's why they're called surprises.

To Marks, this means that investors should not try to get cute, predict the future, and outsmart the market. The best they can do is solid technical analysis of individual companies and invest based on observable facts about value and value creation.

To me, this means that we programmers shouldn't try to prepare for surprises by designing them into our software. Usually, the best we can do is to implement simple, clean code that does just what it does and no more. The only prediction we can make about the future is that we may well have to change our code. Creating clean interfaces and hiding implementation choices enable us to write code that is as straightforward as possible to change when the unimaginable happens, or even the imaginable.

Marks closes this memo with five quotes about forecasting from a collection he has been building for forty years. I like this line from former GE executive Ian Wilson, which expresses the conundrum that every designer faces:

No amount of sophistication is going to allay the fact that all of your knowledge is about the past and all your decisions are about the future.

It isn't really all that strange that the wisdom of an investor like Marks might be of great value to a programmer. Investors and programmers both have to choose today how to use a finite resource in a way that maximizes value now and in the future. Both have to make these choices based on knowledge gleaned from the past. Both are generally most successful when the future looks like the past.

A big challenge for investors and programmers alike is to find ways to use their experience of the past in a way that maximizes value across a number of possible futures, both the ones we can anticipate and the ones we can't.


Posted by Eugene Wallingford | Permalink | Categories: General, Software Development

January 22, 2017 9:26 AM

To Teach is to Counsel Possibility and Patience

As I settle into a new semester of teaching students functional programming and programming languages, I find myself again in the role of grader of, and commenter, on code. This passage from Tobias Wolff in Paris Review interview serves as a guide for me:

Now, did [Pound] teach Eliot to write? No. But he did help him see that there were more notes to be played he was playing. That is the kind of thing I hope to do. And to counsel patience -- the beauty of patience, which is not a virtue of the young.

Students often think that learning to program is all about the correctness of their code. Correctness matters, but there's a lot more. Knowing what is possible and learning to be patient as they learn often matter more than mere correctness. For some students, it seems, those lessons must begin before more technical habits can take hold.


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

January 20, 2017 11:38 AM

Build the Bridge

On the racket-users mailing list yesterday, Matthias Felleisen issued "a research challenge that is common in the Racket world":

If you are here and you see the blueprints for paradise over there, don't just build paradise. Also build the bridge from here to there.

This is one of the things I love about Racket. And I don't use even 1% of the goodness that is Racket and its ecosystem.

Over the last couple of years, I have been migrating my Programming Languages course from a Scheme subset of Racket to Racket itself. Sometimes, this is simply a matter of talking about Racket, not Scheme. Others, it means using some of the data structures, functions, and tools Racket provides rather than doing without or building our own. Occasionally, this shift requires changing something I do in class, because Racket is fussier than Scheme in some regards. That's usually a good thing, because the change makes Racket a better language for engineering big programs. In general, though, the shift goes smoothly.

Occasionally, the only challenge is a personal one. For example, I decided to use first and rest this semester when working with lists, instead of car and cdr. This should make some students' lives better. Learning a new language and a new style and new IDE all at once can be tough for students with only a couple of semesters' programming experience, and using words that mean what they say eliminates one unnecessary barrier. But, as I tweeted, I don't feel whole or entirely clean when I do so. As my college humanities prof taught me through Greek tragedies, old habits die hard, if at all.

One of my goals for the course this semester is to have the course serve as a better introduction to Racket for students who might be inclined to take advantage of its utility and power in later courses, or who simply want to enjoy working in a beautiful language. I always seem to have a few who do, but it might be nice if even more left the course thinking of Racket as a real alternative for their project work. We'll see how it goes.


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

January 10, 2017 4:07 PM

Garbage Collection -- and the Tempting Illusion of Big Breakthroughs

Good advice in this paragraph, paraphrased lightly from Modern Garbage Collection:

Garbage collection is a hard problem, really hard, one that has been studied by an army of computer scientists for decades. Be very suspicious of supposed breakthroughs that everyone else missed. They are more likely to just be strange or unusual tradeoffs in disguise, avoided by others for reasons that may only become apparent later.

It's wise always to be on the lookout for "strange or unusual tradeoffs in disguise".


Posted by Eugene Wallingford | Permalink | Categories: Computing, Patterns, Software Development

December 27, 2016 8:36 AM

There's No Right Way To Write All Programs

In the Paris Review's The Art of Fiction No. 183, the interviewer asks Tobias Wolff for some advice. Wolff demurs:

Writers often give advice they don't follow to the letter themselves. And so I tend to receive their commandments warily.

This was refreshing. I also tend to hear advice from successful people with caution.

Wolff is willing, however, to share stories about what has worked for him. He just doesn't think what works for him will necessarily work for anyone else. He doesn't even think that what works for him on one story will work for him on the next. Eventually, he sums up his advice with this:

There's no right way to tell all stories, only the right way to tell a particular story.

Wolff follows a few core practices that keep him moving forward every day, but he isn't dogmatic about them. He does whatever he needs to do to get the current story written -- even if it means moving to Italy for several months.

Wolfe is taking about short stories and novels, but this sentiment applies to more than writing. It captures what is, for me, the fundamental attitude of agile software developers: There is no right way to write all programs, only a good way to write each particular program. We find that certain programming practices -- taking small steps, writing tests early, refactoring mercilessly, pairing -- apply to most tasks. These practices are so powerful precisely because they give us feedback frequently and help us adjust course quickly.

But when conditions change around us, we must be willing to adapt. (Even if that means moving to Italy for several months.) This is what it means to be agile.


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

December 16, 2016 2:14 PM

Language and Thinking

Earlier this week, Rands tweeted:

Tinkering is a deceptively high value activity.

... to which I followed up:

Which is why a language that enables tinkering is a deceptively high value tool.

I thought about these ideas a couple of days later when I read The Running Conversation in Your Head and came across this paragraph:

The idea is not that you need language for thinking but that when language comes along, it sure is useful. It changes the way you think, it allows you to operate in different ways because you can use the words as tools.

This is how I think about programming in general and about new, and better, programming languages in particular. A programmer can think quite well in just about any language. Many of us cut our teeth in BASIC, and simply learning how to think computationally allowed us to think differently than we did before. But then we learn a radically different or more powerful language, and suddenly we are able to think new thoughts, thoughts we didn't even conceive of in quite the same way before.

It's not that we need the new language in order to think, but when it comes along, it allows us to operate in different ways. New concepts become new tools.

I am looking forward to introducing Racket and functional programming to a new group of students this spring semester. First-class functions and higher-order functions can change how students think about the most basic computations such as loops and about higher-level techniques such as OOP. I hope to do a better job this time around helping them see the ways in which it really is different.

To echo the Running Conversation article again, when we learn a new programming style or language, "Something really special is created. And the thing that is created might well be unique in the universe."


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

December 12, 2016 3:15 PM

Computer Science Is Not That Special

I'm reminded of a student I met with once who told me that he planned to go to law school, and then a few minutes later, when going over a draft of a lab report, said "Yeah... Grammar isn't really my thing." Explaining why I busted up laughing took a while.

When I ask prospective students why they decided not to pursue a CS degree, they often say things to the effect of "Computer science seemed cool, but I heard getting a degree in CS was a lot of work." or "A buddy of mine told me that programming is tedious." Sometimes, I meet these students as they return to the university to get a second degree -- in computer science. Their reasons for returning vary from the economic (a desire for better career opportunities) to personal (a desire to do something that they have always wanted to do, or to pursue a newfound creative interest).

After you've been in the working world a while, a little hard work and some occasional tedium don't seem like deal breakers any more.

Such conversations were on my mind as I read physicist Chad Orzel's recent Science Is Not THAT Special. In this article, Orzel responds to the conventional wisdom that becoming a scientist and doing science involve a lot of hard work that is unlike the exciting stuff that draws kids to science in the first place. Then, when kids encounter the drudgery and hard work, they turn away from science as a potential career.

Orzel's takedown of this idea is spot on. (The quoted passage above is one of the article's lighter moments in confronting the stereotype.) Sure, doing science involves a lot of tedium, but this problem is not unique to science. Getting good at anything requires a lot of hard work and tedious attention to detail. Every job, every area of expertise, has its moments of drudgery. Even the rare few who become professional athletes and artists, with careers generally thought of as dreams that enable people to earn a living doing the thing they love, spend endless hours engaged in the drudgery of practicing technique and automatizing physical actions that become their professional vocabulary.

Why do we act as if science is any different, or should be?

Computer science gets this rap, too. What could be worse than fighting with a compiler to accept a program while you are learning to code? Or plowing threw reams of poorly documented API descriptions to plug your code into someone's e-commerce system?

Personally, I can think of lots of things that are worse. I am under no illusion, however, that other professionals are somehow shielded from such negative experiences. I just prefer my pains to theirs.

Maybe some people don't like certain kinds of drudgery. That's fair. Sometimes we gravitate toward the things whose drudgery we don't mind, and sometimes we come to accept the drudgery of the things we love to do. I'm not sure which explains my fascination with programming. I certainly enjoy the drudgery of computer science more than that of most other activities -- or at least I suffer it more gladly.

I'm with Orzel. Let's be honest with ourselves and our students that getting good at anything takes a lot of hard work and, once you master something, you'll occasionally face some tedium in the trenches. Science, and computer science in particular, are not that much different from anything else.


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

December 05, 2016 2:42 PM

Copying Interfaces, Copying Code

Khoi Vinh wrote a short blog entry called The Underestimated Merits of Copying Someone Else's Work that reminds us how valuable copying others' work, a standard practice in the arts, can be. At the lowest level there is copying at the textual level. Sometimes, the value is mental or mechanical:

Hunter S. Thompson famously re-typed, word for word, F. Scott Fitzgerald's "The Great Gatsby" just to learn how it was done.

This made me think back to the days when people typed up code they found in Byte magazine and other periodicals. Of course, typing a program gave you more than practice typing or a sense of what it was like to type that much; it also gave you a working program that you could use and tinker with. I don't know if anyone would ever copy a short story or novel by hand so that they could morph it into something new, but we can do that meaningfully with code.

I missed the "copy code from Byte" phase of computing. My family never had a home computer, and by the time I got to college and changed my major to CS, I had plenty of new programs to write. I pulled ideas about chess-playing programs and other programs I wanted to write from books and magazines, but I never typed up an entire program's source code. (I mention one of my first personal projects in an old OOPSLA workshop report.)

I don't hear much these days about people copying code keystroke for keystroke. Zed Shaw has championed this idea in a series of introductory programming books such as Learn Python The Hard Way. There is probably something to be learned by copying code Hunter Thompson-style, feeling the rhythm of syntax and format by repetition, and soaking up semantics along the way.

Vinh has a more interesting sort of copying in mind, though: copying the interface of a software product:

It's odd then to realize that copying product interfaces is such an uncommon learning technique in design. ... it's even easier to re-create designs than it is to re-create other forms of art. With a painting or sculpture, it's often difficult to get access to the historically accurate tools and materials that were used to create the original. With today's product design, the tools are readily available; most of us already own the exact same software employed to create any of the most prominent product designs you could name.

This idea generalizes beyond interfaces to any program for which we don't have source code. We often talk about reverse engineering a program, but in my experience this usually refers to creating a program that behaves "just like" the original. Copying an interface pixel by pixel, like copying a program or novel character by character, requires the artist to attend to the smallest details -- to create an exact replica, not a similar work.

We cannot reverse engineer a program and arrive at identical source code, of course, but we can try to replicate behavior and interface exactly. Doing so might help a person appreciate the details of code more. Such a practice might even help a programmer learn the craft of programming in a different way.


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

November 01, 2016 4:04 PM

An Adventure with C++ Compilers

I am a regular reader of John Regehr's blog, which provides a steady diet of cool compiler conversation. One of Regehr's frequent topics is undefined behavior in programming languages, and what that means for implementing and testing compilers. A lot of those blog entries involve C and C++, which I don't use all that often any more, so reading them is more spectator sport than contact sport.

This week, I got see how capricious C++ compilers can feel up close.

My students are implementing a compiler for a simple subset of a Pascal-like language. We call the simplest program in this language print-one:

    $ cat print-one.flr
    program main();
      begin
        return 1
      end.

One of the teams is writing their compiler in C++. The team completed its most recent version, a parser that validates its input or reports an error that renders its input invalid. They were excited that it finally worked:

    $ g++ -std=c++14 compiler.cpp -o compiler
    $ compiler print-one.flr 
    Valid flair program

They had tested their compiler on two platforms:

  • a laptop running OS X v10.11.5 and gcc v4.9.3
  • a desktop running Ubuntu v14.04 and gcc v4.8.4

I sat down at my desktop computer to exercise their compiler.

    $ g++ compiler.cpp -o compiler
    In file included from compiler.cpp:7:
    In file included from ./parser.cpp:3:
    In file included from ./ast-utilities.cpp:4:
    ./ast-utilities.hpp:7:22: warning: in-class initialization of non-static data
          member is a C++11 extension [-Wc++11-extensions]
        std::string name = "Node";
                    ^
    [...]
    24 warnings generated.

Oops, I forgot the -std=c++14 flag. Still, it compiled, and all of the warnings come from a part of the code has no effect on program validation. So I tried the executable:

    $ compiler print-one.flr 
    ERROR at line #3 -- unexpected <invalid>  1
    Invalid flair program

Hmm. The warnings are unrelated to part of the executable that I am testing, but maybe they are creating a problem. So I recompile with the flag:

    $ g++ -std=c++14 compiler.cpp -o compiler
    error: invalid value 'c++14' in '-std=c++14'

What? I check my OS and compiler specs:

    $ sw_vers -productVersion
    10.9.5
    $ g++ --version
    Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
    Apple LLVM version 6.0 (clang-600.0.57) (based on LLVM 3.5svn)
    [...]

Oh, right, Apple doesn't ship gcc any more; it ships clang and link gcc to the clang exe. I know my OS is a bit old, but it still seems odd that the -std=c++14 flag isn't supported. I google for an answer (thanks, StackOverflow!) and find that that I need to use -std=c++1y. Okay:

    $ g++ -std=c++1y compiler.cpp -o compiler
    $ compiler print-one.flr 
    ERROR at line #3 -- unexpected <invalid>  1
    Invalid flair program

Now the student compiler compiles but gives incorrect, or at least unintended, behavior. I'm surprised that both my clang and the students' gcc compile their compiler yet produce executables that give different answers. I know that gcc and clang aren't 100% compatible, but my students are using a relatively small part of C++. How can this be?

Maybe it has something to do with how clang processes the c++1y standard flag. So I backed up to the previous standard:

    $ g++ -std=c++0x compiler.cpp -o compiler
    $ compiler print-one.flr 
    ERROR at line #3 -- unexpected <invalid>  1
    Invalid flair program

Yes, that's c++0x, not c++0y. The student compiler still compiles and still gives incorrect or unintended behavior. Maybe it is a clang problem? I upload their code to our student server, which runs Linux and gcc:

    $ cat /etc/debian_version 
    8.1
    $ g++ --version
    [...]
    gcc version 4.7.2 (Debian 4.7.2-5)

This version of gcc doesn't support either c++14 or c++1?, so I fell back to c++0x:

    $ g++ -std=c++0x compiler.cpp -o compiler
    $ compiler print-one.flr 
    Valid flair program

Hurray! I can test their code.

I'm curious. I have a Macbook Pro running a newer version of OS X. Maybe...

    $ sw_vers -productVersion
    ProductName:Mac OS X
    ProductVersion:10.10.5
    BuildVersion:14F2009
    $ g++ --version
    Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/usr/include/c++/4.2.1
    Apple LLVM version 7.0.2 (clang-700.1.81)
    [...]

$ g++ -std=c++14 compiler.cpp -o compiler $ compiler print-one.flr Valid flair program

Now, the c++14 flag works, and it produces a compiler that produces the correct behavior -- or at least the intended behavior.

I am curious about this anomaly, but not curious enough to research the differences between clang and gcc, the differences between the different versions of clang, or what Apple or Debian are doing. I'm also not curious enough to figure out which nook of C++ my students have stumbled into that could expose a rift in the behavior of these various C++ compilers, all of which are standard tools and pretty good.

At least now I remember what it's like to program in a language with undefined behavior and can read Regehr's blog posts with a knowing nod of the head.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

October 25, 2016 3:33 PM

How to Write Code That Doesn't Get in the Way

Last week some tweeted a link to Write code that is easy to delete, not easy to extend, an old blog entry by @tef from last February. When I read it yesterday, I was nodding my head so hard that I almost fell off of the elliptical machine. I have done that before. Trust me, you don't want to do it. You don't really fall; the machine throws you. If you are moving fast, it throws you hard.

I don't gush over articles in my blog as much these days as I once did, but this one is worthy. If you write code, go read this article. Nothing I write hear will replace reading the entire piece. For my own joy and benefit, though, I record a few of my favorite passages here -- along with comments, as I am wont to do.

... if we wish to count lines of code, we should not regard them as "lines produced" but as "lines spent".

This is actually a quote from EWD 1036, one of Dijkstra's famous notes. I don't always agree with EWD, but this line is gold and a perfect tagline for @tef's entry

Building reusable code is easier to do in hindsight with a couple of examples of use in the code base, than foresight of ones you might want later.

When OO frameworks first became popular, perhaps the biggest mistake that developers made was to try to write a framework up front. Refactoring from multiple programs is still the best way for most of us mortals to create a framework. This advice also applies to cohesive libraries of functions.

Aside: Make a util directory and keep different utilities in different files. A single util file will always grow until it is too big and yet too hard to split apart. Using a single util file is unhygienic.

Golf clap. I have this pattern. I am glad to know that others do, too.

Boiler plate is a lot like copy-pasting, but you change some of the code in a different place each time, rather than the same bit over and over.

For some reason, reading this made me think of copy-and-paste as a common outcome of programming language design, if not its intended effect.

Boilerplate works best when libraries are expected to cater to all tastes, but sometimes there is just too much duplication. It's time to wrap your flexible library with one that has opinions on policy, workflow, and state. Building simple-to-use APIs is about turning your boilerplate into a library.

Again, notice the role refactoring plays here. Build lots of code that works, then factor out boilerplate or wrap it. The API you design will be informed by real uses of the functions you define.

It is not so much that we are hiding detail when we wrap one library in another, but we are separating concerns: requests is about popular http adventures; urllib3 is about giving you the tools to choose your own adventure.

One of the things I like about this blog entry is its theme of separating concerns. Some libraries are perfect when you are building a common application; others enable you to build your own tools when you need something different.

A lot of programming is exploratory, and it's quicker to get it wrong a few times and iterate than think to get it right first time.

Agile Development 101. Even when I know a domain well, if the domain affords me a lot of latitude when building apps, I like explore and iterate as a way to help me choose the right path for the current implementation.

[O]ne large mistake is easier to deploy than 20 tightly coupled ones.

And even more, as @tef emphasizes throughout: It's easier to delete, too.

Becoming a professional software developer is accumulating a back-catalogue of regrets and mistakes.

When we teach students to design programs in their first couple of years of CS, we often tell them that good design comes from experience, and experience comes from bad design. An important step in becoming a better programmer is to start writing code, as much as you can. (That's how you build your catalog of mistakes.) Then think about the results. (That's how you turn mistakes into experience.)

We are not building modules around being able to re-use them, but being able to change them.

This is one of the central lessons of software development. One of the things I loved about OO programming was that it gave me another way to create modules that isolated different concerns from one another. So many folks make the mistake of thinking that objects, classes, and even frameworks are about reuse. But reuse is not the key; separation of concerns is. Design your objects that create shearing layers within your program, which make it easier to change the code.

It isn't so much that you're iterating, but you have a feedback loop.

As I blogged recently, competence is about creating conditions that minimize mistakes but also help you to recognize mistakes quickly and correct them. You don't iterate for the sake of iterating. You iterate because that's how you feed learning back into the work.

The strategies I've talked about [...] are not about writing good software, but how to build software that can change over time.

This blog entry isn't a recipe for writing good code. It's a recipe for creating conditions in which you can write good code. I do claim, though, that all other things being reasonably equal, in most domains, code that you can change is better code than code you can't change.

Good code isn't about getting it right the first time. Good code is just legacy code that doesn't get in the way.

That is a Kent Beck-caliber witticism: Good code is just legacy code that doesn't get in the way.

This blog entry made me happy.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

October 22, 2016 2:00 PM

Competence and Creating Conditions that Minimize Mistakes

I enjoyed this interview with Atul Gawande by Ezra Klein. When talking about making mistakes, Gawande notes that humans have enough knowledge to cut way down on errors in many disciplines, but we do not always use that knowledge effectively. Mistakes come naturally from the environments in which we work:

We're all set up for failure under the conditions of complexity.

Mistakes are often more a matter of discipline and attention to detail than a matter of knowledge or understanding. Klein captures the essence of Gawande's lesson in one of his questions:

We have this idea that competence is not making mistakes and getting everything right. [But really...] Competence is knowing you will make mistakes and setting up a context that will help reduce the possibility of error but also help deal with the aftermath of error.

In my experience, this is a hard lesson for computer science students to grok. It's okay to make mistakes, but create conditions where you make as few as possible and in which you can recognize and deal with the mistakes as quickly as possible. High-discipline practices such as test-first and pair programming, version control, and automated builds make a lot more sense when you see them from this perspective.


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

October 13, 2016 4:29 PM

Shocking News: Design Technique Not Helpful When Design Is Already Done

Thanks to Greg Wilson for a pointer to this paper, which reports the result of an empirical evaluation of the effects of test-driven development on software quality and programmer productivity. In a blog entry about the paper, Wilson writes:

This painstaking study is the latest in a long line to find that test-driven development (TDD) has little or no impact on development time or code quality.

He is surprised, because he feels more productive when he writes tests up-front.

I'd like to be able to say that these researchers and others must be measuring the wrong things, or measuring things the wrong way, but after so many years and so many different studies, those of us who believe might just have to accept that our self-assessment is wrong.

Never fear! Avdi Grimm points the way toward resolution. Section 3.3 of the research paper describes the task that was given to the programmers in the experiment:

The task was divided into 13 user stories of incremental difficulty, each building on the results of the previous one. An example, in terms of input and expected output, accompanied the description of each user story. An Eclipse project, containing a stub of the expected API signature, (51 Java SLOC); also an example JUnit test (9 Java SLOC) was provided together with the task description.

Notice what this says:

  • Test subjects were given the user stories.
  • The stories were sequenced to assist the subjects.
  • Each story was accompanied by an example.
  • Subjects were given code stubs with method signatures already defined.

The paper reports that previous studies of this sort have also set tasks before programmers with similar initial conditions. Grimm identifies a key feature of all these experiments: The problem given to the test subjects has already been defined in great detail.

Shocking news: test-driven design is not helpful when the design is already done!

As Grimm says, TDD helps the programmer think about how to start writing code and when to stop. For me, the most greatest value in doing TDD is that it helps me think about what I need to build, and why. That is design. If the problem is already defined to the point of implementation, most of the essential design thinking has been done. In that context, the results reported in this research paper are thoroughly unsurprising.

Like Grimm, I sympathize with the challenge of doing empirical research on the practices of programmers. I am glad that people such as the paper's authors are doing such research and that people such as Wilson discuss the results. But when we wonder why some research results conflict with the personal assessments of real programmers and our assessments of our own experiences, I think I know what one of the problems might be:

Evaluating the efficacy of a design methodology properly requires that we observe people doing, um, design.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

October 02, 2016 10:03 AM

Tom Wolfe on Writer's Block

In the Paris Review's The Art of Fiction No. 123, Tom Wolfe tells how he learned about writer's block. Wolfe was working at Esquire magazine, and his first editor, Byron Dobell, had assigned him to write an article about car customizers. After doing all his research, he was totally blocked.

I now know what writer's block is. It's the fear you cannot do what you've announced to someone else you can do, or else the fear that it isn't worth doing. That's a rarer form. In this case I suddenly realized I'd never written a magazine article before and I just felt I couldn't do it. Well, Dobell somehow shamed me into writing down the notes that I had taken in my reporting on the car customizers so that some competent writer could convert them into a magazine piece. I sat down one night and started writing a memorandum to him as fast as I could, just to get the ordeal over with. It became very much like a letter that you would write to a friend in which you're not thinking about style, you're just pouring it all out, and I churned it out all night long, forty typewritten, triple-spaced pages. I turned it in in the morning to Byron at Esquire, and then I went home to sleep.

Later that day, Dobell called him to say that they were deleting the "Dear Byron" at the top of the memo and running the piece.

Most of us need more editing than that after we write anything, but... No matter; first you have to write something. Even if it's the product of a rushed all-nighter, just to get an obligation off our table.

When I write, and especially when I program, my reluctance to start usually grows out of a different sort of fear: the fear that I won't be able to stop, or want to. Even simple programming tasks can become deep holes into which we fall. I like that feeling, but I don't have enough control of my work schedule most days to be able to risk disappearing like that. What I could use is an extra dose of audacity or impetuosity. Or maybe a boss like Byron Dobell.


Posted by Eugene Wallingford | Permalink | Categories: General, Software Development

September 27, 2016 2:57 PM

Elrond, Agile Development Sage

Call me a crazy extreme programmer, but when I came across the Tolkien passage quoted in my previous post on commitment and ignorance again recently after many years, my first thought was that Elrond sounded like a wise old agile developer:

Look not too far ahead!

You aren't gonna need it, indeed.

This first thought cast Gimli in the role of a Big Design Up Front developer. Unfortunately, that analogy sells his contribution to the conversation short. Just as Gimli's deep commitment to the mission is balanced by Elrond's awareness, so, too, is Gimli's perspective applied to software balanced by Elrond's YAGNI. Perhaps then Gimli plays the role of Metaphor in this fantasy: the impulse that drives the team forward to the ultimate goal.

Just another one of those agile moments I have every now and then. I wonder if they will start happening with more frequency, and less reality, as I get older. They are a little like senior moments, only focused on programming.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

August 11, 2016 10:49 AM

To Founders in Search of Patience and Low Costs

Nils Pihl, CEO at Traintracks.io, writes about the benefits of launching the start-up in Beijing:

It took two years of hard work and late nights at the whiteboard to build a prototype of something we knew we could be proud of -- and what Silicon Valley investor would agree to fund something that would take two years to release? Not only that, but it would have cost us roughly 6 times as much money to develop it in Silicon Valley -- for no immediate benefit.

If moving to Beijing is not an option for you, fear not. You do not have to travel that far to find patient investors, great programmers, and low cost of living. Try Des Moines. Or St. Louis. Or Indianapolis. Or, if you must live in a Major World City, try Chicago. Even my small city can offer a good starting point, though programmers are not as plentiful as we might like.

The US Midwest has a lot of advantages for founders, but none of the smog you'll find in Beijing and much shorter commutes than you will find in all the places people tell you you have to go.


Posted by Eugene Wallingford | Permalink | Categories: General, Software Development

July 28, 2016 2:37 PM

Functional Programming, Inlined Code, and a Programming Challenge

an example of the cover art for the Commander Keen series of games

I recently came across an old entry on Jonathan Blow's blog called John Carmack on Inlined Code. The bulk of the entry consists an even older email message that Carmack, lead programmer on video games such as Doom and Quake, sent to a mailing list, encouraging developers to consider inlining function calls as a matter of style. This email message is the earliest explanation I've seen of Carmack's drift toward functional programming, seeking to as many of its benefits as possible even in the harshly real-time environment of game programming.

The article is a great read, with much advice borne in the trenches of writing and testing large programs whose run-time performance is key to their success. Some of the ideas involve programming language:

It would be kind of nice if C had a "functional" keyword to enforce no global references.

... while others are more about design style:

The function that is least likely to cause a problem is one that doesn't exist, which is the benefit of inlining it.

... and still others remind us to rely on good tools to help avoid inevitable human error:

I now strongly encourage explicit loops for everything, and hope the compiler unrolls it properly.

(This one may come in handy as I prepare to teach my compiler course again this fall.)

This message-within-a-blog-entry itself quotes another email message, by Henry Spencer, which contains the seeds of a programming challenge. Spencer described a piece of flight software written in a particularly limiting style:

It disallowed both subroutine calls and backward branches, except for the one at the bottom of the main loop. Control flow went forward only. Sometimes one piece of code had to leave a note for a later piece telling it what to do, but this worked out well for testing: all data was allocated statically, and monitoring those variables gave a clear picture of most everything the software was doing.

Wow: one big loop, within which all control flows forward. To me, this sounds like a devilish challenge to take on when writing even a moderately complex program like a scanner or parser, which generally contain many loops within loops. In this regard, it reminds me of the Polymorphism Challenge's prohibition of if-statements and other forms of selection in code. The goal of that challenge was to help programmers really grok how the use of substitutable objects can lead to an entirely different style of program than we tend to create with traditional procedural programming.

Even though Carmack knew that "a great deal of stuff that goes on in the aerospace industry should not be emulated by anyone, and is often self destructive", he thought that this idea might have practical value, so he tried it out. The experience helped him evolve his programming style in a promising direction. This is a great example of the power of the pedagogical pattern known as Three Bears: take an idea to its extreme in order to learn the boundaries of its utility. Sometimes, you will find that those boundaries lie beyond what you originally thought.

Carmack's whole article is worth a read. Thanks to Jonathan Blow for preserving it for us.

~~~~

The image above is an example of the cover art for the "Commander Keen" series of video games, courtesy of Wikipedia. John Carmack was also the lead programmer for this series. What a remarkable oeuvre he has produced.


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

July 27, 2016 10:58 AM

Teaching Programming Versus Teaching Art

Like many people, I am fond of analogies between software development and arts like writing and painting. It's easy to be seduced by similarities even when the daily experiences of programmers and artists are often so different.

For that reason, I was glad that this statement by sculptor Jacques Lipschutz stood out in such great relief from the text around it:

Teaching is death. If he teaches, the sculptor has to open up and reveal things that should be closed and sacred.

For me, teaching computer science has been just the opposite. Teaching forces me to open up my thinking processes. It encourages me to talk with professional developers about how they do what they do and what they think about along the way. Through these discussions, we do reveal things that sometimes feel almost sacred, but I think we all benefit from the examination. It not only helps me to teach novice developers more effectively; it also helps me to be a better programmer myself.

~~~~

(The Lipschutz passage comes from Conversations with Artists, which I quoted for the first time last week.)


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

July 20, 2016 9:16 AM

A Few Quick Lessons from Five Small Joy Programs

I recently wrote about some experiences programming in Joy, in which I use Joy to solve five problems that make up a typical homework assignment early in my Programming Languages course. These problems introduce my students to writing simple functions in a functional style, using Racket. Here is my code, if you care to check it out. I'm just getting back to stack programming, so this code can surely be improved. Feel free to email me suggestions or tweet me at @wallingf!

What did these problems teach me about Joy?

  • The language's documentation is sparse. Like my students, I had to find out which Joy primitives were available to me. It has a lot of the basic arithmetic operators you'd expect, but finding them meant searching through a plain-text file. I should write Racket-caliber documentation for the language to support my own work.

  • The number and order of the arguments to a function matters a lot. A function that takes several arguments can become more complicated than the corresponding Racket function, especially if you need to use them multiple times. I encountered this on my first day back to the language. In Racket, this problem requires a compound expression, but it is relatively straightforward, because arguments have names. With all its arguments on the stack, a Joy function has to do more work simply to access values, let alone replicate them for multiple uses.

  • A slight difference in task can lead to a large change in the code. For Problem 4, I implemented operators for modular addition, subtraction, and multiplication. +mod and *mod were elegant and straightforward. -mod was a different story. Joy has a rem operator that operates like Racket's remainder, but it has no equivalent to modulo. The fact that rem returns negative values means that I need a boolean expression and quoted programs and a new kind of thinking. This militates for a bigger shift in programming style right away.

  • I miss the freedom of Racket naming style. This isn't a knock on Joy, because most every programming language restricts severely the set of characters you can use in identifiers. But after being able to name functions +mod, in-range?, and int->char in Racket, the restrictions feel even more onerous.

  • As in most programming styles, the right answer in Joy is often to write the correct helpers. The difference in level of detail between +mod and *mod on the one hand and -mod on the other indicates that I am missing solution. A better approach is to implement a modulo operator and use it to write all three mod operators. This will hide lower-level details in a general-purpose operator. modulo would make a nice addition to a library of math operators.

  • Even simple problems can excite me about the next step. Several of these solutions, especially the mod operators, cry out for higher-order operators. In Racket, we can factor out the duplication in these operators and create a function that generates these functions for us. In Joy, we can do it, too, using quoted programs of the sort you see in the code for -mod. I'll be moving on to quoted programs in more detail soon, and I can't wait... I know that they will push me farther along the transition to the unique style of stack programming.

It's neat for me to be reminded that even the simplest little functions raise interesting design questions. In Joy, use of a stack for all data values means that identifying the most natural order for the arguments we make available to an operators can have a big effect on the ability to read and write code. In what order will arguments generally appear "in the wild"?

In the course of experimenting and trying to debug my code (or, even more frustrating, trying to understand why the code I wrote worked), I even wrote my first general utility operator:

    DEFINE clear  == [] unstack.

It clears the stack so that I can see exactly what the code I'm about to run creates and consumes. It's the first entry in my own little user library, named utilities.joy.

Fun, fun, fun. Have I ever said that I like to write programs?


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

July 07, 2016 2:01 PM

Oberon: GoogleMaps as Desktop UI

Oberon is a software stack created by Niklaus Wirth and his lab at ETH Zürich. Lukas Mathis describes some of what makes Oberon unusual, including the fact that its desktop is "an infinitely large two-dimensional space on which windows ... can be arranged":

It's incredibly easy to move around on this plane and zoom in and out of it. Instead of stacking windows, hiding them behind each other (which is possible in modern versions of Oberon), you simply arrange them next to each other and zoom out and in again to switch between them. When people held presentations using Oberon, they would arrange all slides next to each other, zoom in on the first one, and then simply slide the view one screen size to the right to go to the next slide.

This sounds like interacting with Google Maps, or any other modern map app. I wonder if anyone else is using this as a model for user interaction on the desktop?

Check out Mathis's article for more. The section "Everything is a Command Line" reminds me of workspaces in Smalltalk. I used to have several workspaces open, with useful snippets of code just waiting for me to do it. Each workspace window was like a custom text-based menu.

I've always liked the idea of Oberon and even considered using the programming language in my compilers course. (I ended up using a variant.) A version of Compiler Construction is now available free online, so everyone can see how Wirth's clear thinking lead to a sparse, complete, elegant whole. I may have to build the latest installment of Oberon and see what all they have working these days.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

June 12, 2016 10:33 AM

The Tension Between Free and Expensive

Yesterday, William Stein's talk about the origins of SageMath spread rapidly through certain neighborhoods of Twitter. It is a thorough and somewhat depressing discussion of how hard it is to develop open source software within an academic setting. Writing code is not part of the tenure reward system or the system for awarding grants. Stein has tenure at the University of Washington but has decided that he has to start a company, SageMath, work for it full-time in order to create a viable open source alternative to the "four 'Ma's": Mathematica, Matlab, Maple, and Magma.

Stein's talk reminded me of something I read earlier this year, from a talk by Matthew Butterick:

"Information wants to be expensive, because it's so valuable ... On the other hand, information wants to be free, because the cost of getting it out is getting lower ... So you have these two fighting against each other."

This was said by a guy named Stewart Brand, way back in 1984.

So what's the message here? Information wants to be free? No, that's not the message. The message is that there are two forces in tension. And the challenge is how to balance the forces.

Proponents of open source software -- and I count myself one -- are often so glib with the mantra "information wants to be free" that we forget about the opposing force. Wolfram et al. have capitalized quite effectively on information's desire to be expensive. This force has an economic power that can overwhelm purely communitarian efforts in many contexts, to the detriment of open work. The challenge is figuring out how to balance the forces.

In my mind, Mozilla stands out as the modern paradigm of seeking a way to balance the forces between free and expensive, creating a non-profit shell on top of a commercial foundation. It also seeks ways to involve academics in process. It will be interesting to see whether this model is sustainable.

Oh, and Stewart Brand. He pointed out this tension thirty years ago. I recently recommended How Buildings Learn to my wife and thought I should look back at the copious notes I took when I read it twenty years ago. But I should read the book again myself; I hope I've changed enough since then that reading it anew brings new ideas to mind.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

May 27, 2016 1:38 PM

Brilliance Is Better Than Magic, Because You Get To Learn It

Brent Simmons has recently suggested that Swift would be better if it were more dynamic. Some readers have interpreted his comments as an unwillingness to learn new things. In Oldie Complains About the Old Old Ways, Simmons explains that new things don't bother him; he simply hopes that we don't lose access to what we learned in the previous generation of improvements. The entry is short and worth reading in its entirety, but the last sentence of this particular paragraph deserves to be etched in stone:

It seemed like magic, then. I later came to understand how it worked, and then it just seemed like brilliance. (Brilliance is better than magic, because you get to learn it.)

This gets to close to the heart of why I love being a computer scientist.

So many of the computer programs I use every day seem like magic. This might seem odd coming from a computer scientist, who has learned how to program and who knows many of the principles that make complex software possible. Yet that complexity takes many forms, and even a familiar program can seem like magic when I'm not thinking about the details under its hood.

As a computer scientist, I get to study the techniques that make these programs work. Sometimes, I even get to look inside the new program I am using, to see the algorithms and data structures that bring to life the experience that feels like magic.

Looking under the hood reminds me that it's not really magic. It isn't always brilliance either, though. Sometimes, it's a very cool idea I've never seen or thought about before. Other times, it's merely a bunch of regular ideas, competently executed, woven together in a way that give an illusion of magic. Regular ideas, competently executed, have their own kind of beauty.

After I study a program, I know the ideas and techniques that make it work. I can use them to make my own programs.

This fall, I will again teach a course in compiler construction. I will tell a group of juniors and seniors, in complete honesty, that every time I compile and execute a program, the compiler feels like magic to me. But I know it's not. By the end of the semester, they will know what I mean; it won't feel like magic to them any more, either. They will have learned how their compilers work. And that is even better than the magic, which will never go away completely.

After the course, they will be able to use the ideas and techniques they learn to write their own programs. Those programs will probably feel like magic to the people who use them, too.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Personal, Software Development

May 05, 2016 1:45 PM

Philosopher-Programmer

In her 1942 book Philosophy in a New Key, philosopher Susanne Langer wrote:

A question is really an ambiguous proposition; the answer is its determination.

This sounds like something a Prolog programmer might say in a philosophical moment. Langer even understood how tough it can be to write effective Prolog queries:

The way a question is asked limits and disposes the ways in which any answer to it -- right or wrong -- may be given.

Try sticking a cut somewhere and see what happens...

It wouldn't be too surprising if a logical philosopher reminded me of Prolog, but Langer's specialties were consciousness and aesthetics. Now that I think about it, though, this connection makes sense, too.

Prolog can be a lot of fun, though logic programming always felt more limiting to me than most other styles. I've been fiddling again with Joy, a language created by a philosopher, but every so often I think I should earmark some time to revisit Prolog someday.


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

May 03, 2016 4:19 PM

Pair Programming is a Skill to be Learned

David Andersen offers a rather thorough list of ways that academics might adapt Google's coding practices to their research. It's a good read; check it out! I did want to comment on one small comment, because it relates to a common belief about pair programming:

But, of course, effective pair programming requires a lot of soft skills and compatible pairs. I'm not going to pretend that this solution works everywhere.

I don't pretend that pair programming works everywhere, either, or that everyone should adopt it, but I often wonder about statements like this one. Andersen seems to think that pair programming is a good thing and has helped him and members of his team's to produce high-quality code in the past. Why downplay the practice in a way he doesn't downplay other practices he recommends?

Throughout, the article encourages the use of new tools and techniques. These tools will alter the practice of his students. Some are complex enough that they will need to be taught, and practiced over some length of time, before they become an effective part of the team's workflow. To me, pair programming is another tool to be learned and practiced. It's certainly no harder than learning git...

Pair programming is a big cultural change for many programmers, and so it does require some coaching and extended practice. This isn't much different than the sort of "onboarding" that Andersen acknowledges will be necessary if he is to adopt some of Google's practices successfully in his lab upon upon his return. Pair programming takes practice and time, too, like most new skills.

I have seen the benefit of pair programming in an academic setting myself. Back when I used to teach our introductory course to freshmen, I had students pair every week in the closed lab sessions. We had thirty students in each section, but only fifteen computers in our lab. I paired students in a rotating fashion, so that over the course of fifteen weeks each student programmed with fifteen different classmates. We didn't use a full-on "pure" XP-style of pairing, but what we did was consistent with the way XP encourages pair programming.

This was a good first step for students. They got to know each other well and learned from one another. The better students often helped their partners in the way senior developers can help junior developers progress. In almost all cases, students helped each other find and fix errors. Even though later courses in the curriculum did not follow up with more pair programming, I saw benefits in later courses, in the way students interacted in the lab and in class.

I taught intro again a couple of falls ago after a long time away. Our lab has twenty-eight machines now, so I was not forced to use pair programming in my labs. I got lazy and let them work solo, with cross-talk. In the end, I regretted it. The students relied on me a lot more to help them find errors in their code, and they tended to work in the same insulated cliques throughout the semester. I don't think the group progressed as much as programmers, either, even though some individuals turned out fine.

A first-year intro lab is a very different setting than a research lab full of doctoral students. However, if freshmen can learn to pair program, I think grad students can, too.

Pair programming is more of a social change than a technical change, and that creates different issues than, say, automated testing and style checking. But it's not so different from the kind of change that capricious adherence to style guidelines or other kinds of code review impose on our individuality.

Are we computer scientists so maladjusted socially that we can't -- or can't be bothered -- to learn the new behaviors we need to program successfully in pairs? In my experience, no.

Like Andersen, I'm not advocating that anyone require pair programming in a lab. But: If you think that the benefits of pair programming exceed the cost, then I encourage you to consider having your research students or even your undergrads use it. Don't shy away because someone else thinks it can't work. Why deprive your students of the benefits?

The bottom line is this. Pair programming is a skill to be learned, like many others we teach our students.


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

April 29, 2016 3:30 PM

A Personal Pantheon of Programming Books

Michael Fogus, in the latest issue of Read-Eval-Print-λove, writes:

The book in question was Thinking Forth by Leo Brodie (Brodie 1987) and upon reading it I immediately put it into my own "personal pantheon" of influential programming books (along with SICP, AMOP, Object-Oriented Software Construction, Smalltalk Best Practice Patterns, and Programmers Guide to the 1802).

Mr. Fogus has good taste. Programmers Guide to the 1802 is new to me. I guess I need to read it.

The other five books, though, are in my own pantheon influential programming books. Some readers may be unfamiliar with these books or the acronyms, or aware that so many of them are available free online. Here are a few links and details:

  • Thinking Forth teaches us how to program in Forth, a concatenative language in which programs run against a global stack. As Fogus writes, though, Brodie teaches us so much more. He teaches a way to think about programs.

  • SICP is Structure and Interpretation of Computer Programs, hailed by many as the greatest book on computer programming ever written. I am sympathetic to this claim.

  • AMOP is The Art of the Metaobject Protocol, a gem of a book that far too few programmers know about. It presents a very different and more general kind of OOP than most people learn, the kind possible in a language like Common Lisp. I don't know of an authorized online version of this book, but there is an HTML copy available.

  • Object-Oriented Software Construction is Bertrand Meyer's opus on OOP. It did not affect me as deeply as the other books on this list, but it presents the most complete, internally consistent software engineering philosophy of OOP that I know of. Again, there seems to be an unauthorized version online.

  • I love Smalltalk Best Practice Patterns and have mentioned it a couple of times over the years [ 1 | 2 ]. Ounce for ounce, it contains more practical wisdom for programming in the trenches than any book I've read. Don't let "Smalltalk" in the title fool you; this book will help you become a better programmer in almost any language and any style. I have a PDF of a pre-production draft of SBPP, and Stephane Ducasse has posted a free online copy, with Kent's blessing.

Paradigms of Artificial Intelligence Programming

There is one book on my own list that Fogus did not mention: Paradigms of Artificial Intelligence Programming, by Peter Norvig. It holds perhaps the top position in my personal pantheon. Subtitled "Case Studies in Common Lisp", this book teaches Common Lisp, AI programming, software engineering, and a host of other topics in a classical case studies fashion. When you finish working through this book, you are not only a better programmer; you also have working versions of a dozen classic AI programs and a couple of language interpreters.

Reading Fogus's paragraph of λove for Thinking Forth brought to mind how I felt when I discovered PAIP as a young assistant professor. I once wrote a short blog entry praising it. May these paragraphs stand as a greater testimony of my affection.

I've learned a lot from other books over the years, both books that would fit well on this list (in particular, A Programming Language by Kenneth Iverson) and others that belong on a different list (say, Gödel, Escher, Bach -- an almost incomparable book). But I treasure certain programming books in a very personal way.


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

March 25, 2016 2:39 PM

Dan Luu on Playing Moneyball with Programmers

Dan Luu's blog is usually both entertaining and insightful. We Only Hire The Trendiest is no exception.

I did my undergrad at Wisconsin, which is one of the 25 schools that claims to be a top 10 cs/engineering school...

Even though he comes from one of the best CS schools, Luu recognizes that grads of many other schools are well prepared for careers in industry. Companies that bias their hiring toward the top schools miss out on a lot of "talent". Then again, they miss out on a lot of great talent in many other ways, too. For example:

A typical rejection reason was something like "we process millions of transactions per day here and we really need someone with more relevant experience who can handle these things without ramping up".

The people you don't hire won't have to ramp up. There is only one problem: You didn't hire anyone, so there's no way they can help you handle these things. Maybe you should hire people with strong foundations, a little curiosity, and a little drive. Those people can develop all the relevant experience you need.

As Luu says, "It's much easier to hire people who are underrated, especially if you're not paying market rates." That's where the Moneyball analogy comes in handy. I wonder if any company is doing sabermetric-like analysis of software developers? If so, they could develop a durable competitive advantage in hiring.

Software entrepreneurs and companies in my part of the world, the American Midwest, have always faced stiff challenges when it comes to hiring and retaining tech talent from the coasts. Luu reminds them that they also have an opportunity: find underrated people from non-elite schools who want to stay in the Midwest, and then develop a team of professionals who rival in performance anything you can find on the coasts.

In my town, Banno is a great example of a company that has accepted this challenge. It's not easy, but with patience and strong leadership, it seems to be working.


Posted by Eugene Wallingford | Permalink | Categories: Managing and Leading, Software Development

March 18, 2016 9:58 AM

Thoughts for Programmers from "Stay on the Bus"

Somehow, I recently came across a link to Stay on the Bus, an excerpt from a commencement speech Arno Rafael Minkkinen gave at the New England School of Photography in June 2004. It is also titled "The Helsinki Bus Station Theory: Finding Your Own Vision in Photography". I almost always enjoy reading the thoughts of an artist on his or her own art, and this was no exception. I also usually hear echoes of what I feel about my own arts and avocations. Here are three.

What happens inside your mind can happen inside a camera.

This is one of the great things about any art. What happens inside your mind can happen in a piano, on a canvas, or in a poem. When people find the art that channels their mind best, beautiful things -- and lives -- can happen.

One of the things I like about programming is that is really a meta-art. Whatever happens in your mind can happen inside a camera, inside a piano, on a canvas, or in a poem. Yet whatever happens inside a camera, inside a piano, or on a canvas can happen inside a computer, in the form of a program. Computing is a new medium for experimenting, simulating, and creating.

Teachers who say, "Oh, it's just student work," should maybe think twice about teaching.

Amen. There is no such thing as student work. It's the work our students are ready to make at a particular moment in time. My students are thinking interesting thoughts and doing their best to make something that reflects those thoughts. Each program, each course in their study is a step along a path.

All work is student work. It's just that some of us students are at a different point along our paths.

Georges Braque has said that out of limited means, new forms emerge. I say, we find out what we will do by knowing what we will not do.

This made me think of an entry I wrote many years ago, Patterns as a Source of Freedom. Artists understand better than programmers sometimes that subordinating to a form does not limit creativity; it unleashes it. I love Minkkinen's way of saying this: we find out what we will do by knowing what we will not do. In programming as in art, it is important to ask oneself, "What will I not do?" This is how we discover we will do, what we can do, and even what we must do.

Those are a few of the ideas that stood out to me as I read Minkkinen's address. The Helsinki Bus Station Theory is a useful story, too.


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

March 02, 2016 4:45 PM

Why Bother With Specialty Languages?

In Sledgehammers vs Nut Crackers, Thomas Guest talks about pulling awk of the shelf to solve a fun little string-processing problem. He then shows a solution in Python, one of his preferred general-purpose programming languages. Why bother with languages like awk when you have Python at the ready? Guest writes:

At the outset of this post I admitted I don't generally bother with awk. Sometimes, though, I encounter the language and need to read and possibly adapt an existing script. So that's one reason to bother. Another reason is that it's elegant and compact. Studying its operation and motivation may help us compose and factor our own programs -- programs far more substantial than the scripts presented here, and in which there will surely be places for mini-languages of our own.

As I watch some of my students struggle this semester to master Racket, recursive programming, and functional style, I offer them hope that learning a new language and a new style will make them better Python and Java programmers, even if they never write another Racket or Lisp program again. The more different ways we know how to think about problems and solutions, the more effective we can be as solvers of problems. Of course, Racket isn't a special purpose language, and a few students find they so like the new style that they stick with the language as their preferred tool.

Experienced programmers understand what Guest is saying, but in the trenches of learning, it can be hard to appreciate the value of knowing different languages and being able to think in different ways. My sledgehammer works fine, my students say; why am I learning to use a nutcracker? I have felt that sensation myself.

I try to keep this feeling in mind as my students work hard to master a new way of thinking. This helps me empathize with their struggle, all the while knowing that Racket will shape how some of them think about every program they write in the future.


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

January 15, 2016 4:02 PM

This Week's Edition of "Amazed by Computers"

As computer scientists get older, we all find ourselves reminiscing about the computers we knew in the past. I sometimes tell my students about using 5.25" floppies with capacities listed in kilobytes, a unit for which they have no frame of reference. It always gets a laugh.

In a recent blog entry, Daniel Lemire reminisces about the Cray 2, "the most powerful computer that money could buy" when he was in high school. It was took up more space than an office desk (see some photos here), had 1 GB of memory, and provided a peak performance of 1.9 gigaflops. In contrast, a modern iPhone fits in a pocket, has 1 GB of memory, too, and contains a graphics processing unit that provides more gigaflops than the Cray 2.

I saw Lemire's post a day after someone tweeted this image of a 64 GB memory card from 2016 next to a 2 GB Western Digital hard drive from 1996:

a 64 GB memory card (2016), a 2 GB hard drive (1996)

The youngest students in my class this semester were born right around 1996. Showing them a 1996 hard drive is like my college professors showing me magnetic cores: ancient history.

This sort of story is old news, of course. Even so, I occasionally remember to be amazed by how quickly our hardware gets smaller and faster. I only wish I could improve my ability to make software just as fast. Alas, we programmers must deal with the constraints of human minds and human organizations. Hardware engineers do battle only with the laws of the physical universe.

Lemire goes a step beyond reminiscing to close his entry:

And what if, today, I were to tell you that in 40 years, we will be able to fit all the computational power of your phone into a nanobot that can live in your blood stream?

Imagine the problems we can solve and the beauty we can make with such hardware. The citizens of 2056 are counting on us.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

December 27, 2015 8:35 AM

The Instinct To Discard Code Is A Kind Of Faith

I learned this one summer while writing and deleting the same program several times:

The instinct to discard is finally a kind of faith. It tells me there's a better way to do this page even though the evidence is not accessible at the present time.

The engineer in me always whispered that evidence supported the desire to delete the program and start over: a recognition that I understood encapsulation of behavior more clearly, or messages as a means of decoupling subsystems. Yet in the end there is also small bit of faith. "Surely some of the code I'm deleting is good enough to survive to the next generation..." The programmer, like the writer, must be willing to believe in such situations that "nature will restore itself".

(The above passage is a quote of Don DeLillo from The Paris Review, The Art of Fiction No. 135.)


Posted by Eugene Wallingford | Permalink | Categories: Software Development

December 09, 2015 2:54 PM

What Is The Best Way Promote a Programming Language?

A newcomer to the Racket users mailing list asked which was the better way to promote the language: start a discussion on the mailing list, or ask questions on Stack Overflow. After explaining that neither was likely to promote Racket, Matthew Butterick gave some excellent advice:

Here's one good way to promote the language:
  1. Make something impressive with Racket.
  2. When someone asks "how did you make that?", give Racket all the credit.

Don't cut corners in Step 1.

This technique applies to all programming languages.

Butterick has made something impressive with Racket: Practical Typography, an online book. He wrote the book using a publishing system named Pollen, which he created in Racket. It's a great book and a joy to read, even if typography is only a passing interest. Check it out. And he gives Racket and the Racket team a lot of credit.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

October 18, 2015 10:42 AM

What a Tiny Language Can Teach Us About Gigantic Systems

StrangeLoop is long in the books for most people, but I'm still thinking about some of the things I learned there. This is the first of what I hope to be a few more posts on talks and ideas still on my mind.

The conference opened with a keynote address by Peter Alvaro, who does research at the intersection of distributed systems and programming languages. The talk was titled "I See What You Mean", but I was drawn in more by his alternate title: "What a Tiny Language Can Teach Us About Gigantic Systems". Going in, I had no idea what to expect from this talk and so, in an attitude whose pessimism surprised me, I expected very little. Coming out, I had been surprised in the most delightful way.

Alvaro opened with the confounding trade-off of all abstractions: Hiding the distracting details of a system can illuminate the critical details (yay!), but the boundaries of an abstraction lock out the people who want to work with the system in a different way (boo!). He illustrated the frustration felt by those who are locked out with a tweet from @pxlplz:

SELECT bs FROM table WHERE sql="arrgh" ORDER BY hate

From this base, Alvaro moved on to his personal interests: query languages, semantics, and distributed systems. When modeling distributed systems, we want a language that is resilient to failure and tolerant of a loose ordering on the execution of operations. But we also need a way to model what programs written in the language mean. The common semantic models express a common split in computing:

  • operational semantics: a program means what it does
  • model-theoretic semantics: a program means the set of facts that makes it true

With query languages, we usually think of programs in terms of the databases of facts that makes them true. In many ways, the streaming data of a distributed system is a dual to the database query model. In the latter, program control flows down to fixed data. In distributed systems, data flows down to fixed control units. If I understood Alvaro correctly, his work seeks to find a sweet spot amid the tension between these two models.

Alvaro walked through three approaches to applicative programming. In the simplest form, we have three operators: select (σ), project (Π), and join (). The database language SQL adds to this set negation (¬). The Prolog subset Datalog makes computation of the least fixed point a basic operation. Datalog is awesome, says Alvaro, but not if you add ¬! That creates a language with too much power to allow the kind of reasoning we want to do about a program.

Declarative programs don't have assignment statements, because they introduce time into a model. An assignment statement effectively partitions the past (in which an old value holds) from the present (characterized by the current value). In a program with state, there is an hidden clock inside the program.

We all know the difficulty of managing state in a standard system. Distributed systems create a new challenge. They need to deal with time, but a relativistic time in which different programs seem to be working on their own timelines. Alvaro gave a couple of common examples:

  • a sender crashes, then restarts and begins to replay a set of transaction
  • a receiver enters garbage collection, then comes back to life and begins to respond to queued messages

A language that helps us write better distributed systems must give us a way to model relativistic time without a hidden universal clock. The rest of the talk looked at some of Alvaro's experiments aimed at finding such languages for distributed systems, building on the ideas he had introduced earlier.

The first was Dedalus, billed as "Datalog in time and space". In Dedalus, knowledge is local and ephemeral. It adds two temporal operators to the set found in SQL: @next, for making assertions about the future, and @async, for making assertions of independence between operations. Computation in Dedalus is rendezvous between data and control. Program state is a deduction.

But what of semantics? Alas, a Dedalus program has an infinite number of models, each model itself infinite. The best we can do is to pull at all of the various potential truths and hope for quiescence. That's not comforting news if you want to know what your program will mean while operating out in the world.

Dedalus as the set of operations {σ, Π, , ¬, @next, @async} takes us back to the beginning of the story: too much power for effective reasoning about programs.

However, Dedalus minus ¬ seems to be a sweet spot. As an abstraction, it hides state representation and control flow and illuminates data, change, and uncertainty. This is the direction Alvaro and his team are moving in now. One result is Bloom, a small new language founded on the Dedalus experiment. Another is Blazes, a program analysis framework that identifies potential inconsistencies in a distributed program and generates the code needed to ensure coordination among the components in question. Very interesting stuff.

Alvaro closed by returning to the idea of abstraction and the role of programming language. He is often asked why he creates new programming languages rather than working in existing languages. In either approach, he points out, he would be creating abstractions, whether with an API or a new syntax. And he would have to address the same challenges:

  • Respect users. We are they.
  • Abstractions leak. Accept that and deal with it.
  • It is better to mean well than to feel good. Programs have to do what we need them to do.

Creating a language is an act of abstraction. But then, so is all of programming. Creating a language specific to distributed systems is a way to make very clear what matters in the domain and to provide both helpful syntax and clear, reliable semantics.

Alvaro admits that this answer hides the real reason that he creates new languages:

Inventing languages is dope.

At the end of this talk, I understood its title, "I See What You Mean", better than I did before it started. The unintended double entendre made me smile. This talk showed how language interacts with problems in all areas of computing, the power language gives us as well as the limits it imposes. Alvaro delivered a most excellent keynote address and opened StrangeLoop on a high note.

Check out the full talk to learn about all of this in much greater detail, with the many flourishes of Alvaro's story-telling.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

October 08, 2015 4:20 PM

Marick's Law

This morning, I wanted to send Michael Feathers a link to Marick's Law. The only link I could find to it was a tweet of Brian's. This law is too important to be left vulnerable to the vagaries of an internet service, so let's give it a permanent home:

In software, anything of the form "X's Law" is better understood by replacing the word "Law" with "Fervent Desire".

This is a beautiful observation, lovingly and consciously self-referential. I think of it almost daily. Use it well.

~~~~~

Historical note.    When I searched for Marick's Law, I did find reference to another law going by the same name. Uncle Bob calls this Marick's Law: "When it comes to code, it never pays to rush." This is a useful aphorism as well, and perhaps Brian once called it Marick's Law, too. Uncle Bob's post is dated November 2008. Brian's coining tweet is dated April 2009. I'm going to stick with the first-person post as definitive and observe that Brian, like Whitman, is large and contains multitudes.

I cannot help but notice that we can and should apply the definitive Marick's Law to the secondhand quote given by Uncle Bob. Many of us fervently desire it to be true that, when it comes to code, it never pays to rush. If it's not, then many of our best practices need an overhaul. Besides, we fear deep in our hearts that sometimes it probably does pay to rush.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

September 22, 2015 2:57 PM

"Good Character" as an Instance of Postel's Law

Mike Feathers draws an analogy I'd never thought of before in The Universality of Postel's Law: what we think of as "good character" can be thought of as an application of Postel's Law to ordinary human relations.

Societies often have the notion of 'good character'. We can attempt all sorts of definitions but at its core, isn't good character just having tolerance for the foibles of others and being a person people can count on? Accepting wider variation at input and producing less variation at output? In systems terms that puts more work on the people who have that quality -- they have to have enough control to avoid 'going off' on people when others 'go off on them', but they get the benefit of being someone people want to connect with. I argue that those same dynamics occur in physical systems and software systems that have the Postel property.

These days, most people talk about Postel's Law as a social law, and criticisms of it even in software design refer to it as creating moral hazards for designers. But Postel coined this "principle of robustness" as a way to talk about implementing TCP, and most references I see to it now relate to HTML and web browsers. I think it's pretty cool when a software design principle applies more broadly in the design world, or can even be useful for understanding human behavior far removed from computing. That's the sign of a valuable pattern -- or anti-pattern.


Posted by Eugene Wallingford | Permalink | Categories: Computing, General, Patterns, Software Development

September 19, 2015 11:56 AM

Software Gets Easier to Consume Faster Than It Gets Easier to Make

In What Is the Business of Literature?, Richard Nash tells a story about how the ideas underlying writing, books, and publishing have evolved over the centuries, shaped by the desires of both creators and merchants. One of the key points is that technological innovation has generally had a far greater effect on the ability to consume literature than on the ability to create it.

But books are just one example of this phenomenon. It is, in fact, a pattern:

For the most part, however, the technical and business-model innovations in literature were one-sided, far better at supplying the means to read a book than to write one. ...

... This was by no means unique to books. The world has also become better at allowing people to buy a desk than to make a desk. In fact, from medieval to modern times, it has become easier to buy food than to make it; to buy clothes than to make them; to obtain legal advice than to know the law; to receive medical care than to actually stitch a wound.

One of the neat things about the last twenty years has been the relatively rapid increase in the ability for ordinary people to to write and disseminate creative works. But an imbalance remains.

Over a shorter time scale, this one-sidedness has been true of software as well. The fifty or sixty years of the Software Era have given us seismic changes in the availability, ubiquity, and backgrounding of software. People often overuse the word 'revolution', but these changes really have had an immense effect in how and when almost everyone uses software in their lives.

Yet creating software remains relatively difficult. The evolution of our tools for writing programs hasn't kept pace with the evolution in platforms for using them. Neither has the growth in our knowledge of how make great software.

There is, of course, a movement these days to teach more people how to program and to support other people who want to learn on their own. I think it's wonderful to open doors so that more people have the opportunity to make things. I'm curious to see if the current momentum bears fruit or is merely a fad in a world that goes through fashions faster than we can comprehend them. It's easier still to toss out a fashion that turns out to require a fair bit of work.

Writing software is still a challenge. Our technologies have not changed that fact. But this is also true, as Nash reminds us, of writing books, making furniture, and a host of other creative activities. He also reminds us that there is hope:

What we see again and again in our society is that people do not need to be encouraged to create, only that businesses want methods by which they can minimize the risk of investing in the creation.

The urge to make things is there. Give people the resources they need -- tools, knowledge, and, most of all, time -- and they will create. Maybe one of the new programmers can help us make better tools for making software, or lead us to new knowledge.


Posted by Eugene Wallingford | Permalink | Categories: Computing, General, Patterns, Software Development

September 18, 2015 3:17 PM

Confidence and Small, Clear Code

Net Prophet, aka Scott Turner, is porting the Pain Machine, his college hoops prediction system, from Common Lisp to Python. The new program is getting different values than the old one in one portion of the code, though they don't seem to affect model's overall performance. Which program is right?

I suspect the Python version is probably "more correct" than the Common Lisp version, because this is a matrix-manipulation heavy part of the code, and it is expressed much more succinctly and clearly in Python.

Scott's a darn good programmer and someone with a lot of Lisp experience, so don't go there. This isn't a language testimonial. It's a testament to how programmers' confidence in their code goes up when they can see more clearly that it says what they intended to say. It is easier to trust something we understand. (But don't forget to run some tests, too!)


Posted by Eugene Wallingford | Permalink | Categories: Software Development

August 19, 2015 4:07 PM

Working Too Much Means Never Having to Say "No"

Among the reasons David Heinemeier Hansson gives in his advice to Fire the Workaholics is that working too much is a sign of bad judgment:

If all you do is work, your value judgements are unlikely to be sound. Making good calls on "is it worth it?" is absolutely critical to great work. Missing out on life in general to put more hours in at the office screams "misguided values".

I agree, in two ways. First, as DHH says, working too much is itself a general indicator that your judgment is out of whack. Second is the more specific case:

For workaholics, doing more work always looks like a reasonable option. As a result, when you are trying to decide, "Should I make this or not?", you never have to choose not to make the something in question -- even when not making it is the right thing to do. That sort of indifferent decision making can be death in any creative endeavor.


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

July 29, 2015 2:10 PM

How Do You Know If It Is Good? You Don't.

In the Paris Review's Garrison Keillor, The Art of Humor No. 2, Keillor thinks back to his decision to become a writer, which left him feeling uncertain about himself:

Someone once asked John Berryman, How do you know if something you've written is good? And John Berryman said, You don't. You never know, and if you need to know then you don't want to be a writer.

This doesn't mean that you don't care about getting better. It means that you aren't doing it to please someone else, or at least that your doing it is not predicated on what someone else thinks. You are doing it because that's what you think about. It means that you keep writing, whether it's good or not. That's how you get better.

It's always fun to watch our students wrestle with this sort of uncertainty and come out on the other side of the darkness. Last fall, I taught first-semester freshmen who were just beginning to find out if they wanted to be programmers or computer scientists, asking questions and learning a lot about themselves. This fall, I'm teaching our senior project course, with students who are nearing the end of their time at the university. Many of them think a lot about programming and programming languages, and they will drive the course with their questions and intensity. As a teacher, I enjoy both ends of the spectrum.


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

July 27, 2015 2:23 PM

The Flip Side to "Programming for All"

a thin volume of William Blake

We all hear the common refrain these days that more people should learn to program, not just CS majors. I agree. If you know how to program, you can make things. Even if you don't write many programs yourself, you are better prepared to talk to the programmers who make things for you. And even if you don't need to talk to programmers, you have expanded your mind a bit to a way of thinking that is changing the world we live in.

But there are two sides to this equation, as Chris Crawford laments in his essay, Fundamentals of Interactivity:

Why is it that our entertainment software has such primitive algorithms in it? The answer lies in the people creating them. The majority are programmers. Programmers aren't really idea people; they're technical people. Yes, they use their brains a great deal in their jobs. But they don't live in the world of ideas. Scan a programmer's bookshelf and you'll find mostly technical manuals plus a handful of science fiction novels. That's about the extent of their reading habits. Ask a programmer about Rabelais, Vivaldi, Boethius, Mendel, Voltaire, Churchill, or Van Gogh, and you'll draw a blank. Gene pools? Grimm's Law? Gresham's Law? Negentropy? Fluxions? The mind-body problem? Most programmers cannot be troubled with such trivia. So how can we expect them to have interesting ideas to put into their algorithms? The result is unsurprising: the algorithms in most entertainment products are boring, predictable, uninformed, and pedestrian. They're about as interesting in conversation as the programmers themselves.

We do have some idea people working on interactive entertainment; more of them show up in multimedia than in games. Unfortunately, most of the idea people can't program. They refuse to learn the technology well enough to express themselves in the language of the medium. I don't understand this cruel joke that Fate has played upon the industry: programmers have no ideas and idea people can't program. Arg!

My office bookshelf occasionally elicits a comment or two from first-time visitors, because even here at work I have a complete works of Shakespeare, a thin volume of William Blake (I love me some Blake!), several philosophy books, and "The Brittanica Book of Usage". I really should have some Voltaire here, too. I do cover one of Crawford's bases: a recent blog entry made a software analogy to Gresham's Law.

In general, I think you're more likely to find a computer scientist who knows some literature than you are to find a literary professional who knows much CS. That's partly an artifact of our school system and partly a result of the wider range historically of literature and the humanities. It's fun to run into a colleague from across campus who has read deeply in some area of science or math, but rare.

However, we are all prone to fall into the chasm of our own specialties and miss out on the well-roundedness that makes us better at whatever specialty we practice. That's one reason that, when high school students and their parents ask me what students should take to prepare for a CS major, I tell them: four years of all the major subjects, including English, math, science, social science, and the arts; plus whatever else interests them, because that's often where they will learn the most. All of these topics help students to become better computer scientists, and better people.

And, not surprisingly, better game developers. I agree with Crawford that more programmers should be learn enough other stuff to be idea people, too. Even if they don't make games.


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

July 13, 2015 2:51 PM

Thinking in Code

A conversation this morning with a student reminded me of a story one of our alumni, a local entrepreneur, told me about his usual practice whenever he has an idea for a new system or a new feature for an existing system.

The alum starts by jotting the idea down in Java, Scala, or some other programming language. He puts this sketch into a git repository and uses the readme.md file to document his thought process. He also records there links to related systems, links to papers on implementation techniques, and any other resources he thinks might be handy. The code itself can be at varying levels of completeness. He allows himself to work out some of the intermediate steps in enough detail to make code work, while leaving other parts as skeletons.

This approach helps him talk to technical customers about the idea. The sketch shows what the idea might look like at a high level, perhaps with some of the intermediate steps running in some useful way. The initial draft helps him identify key development issues and maybe even a reasonable first estimate for how long it would take to flesh out a complete implementation. By writing code and making some of it work, the entrepreneur in him begins to see where the opportunities for business value lie.

If he decides that the idea is worth a deeper look, he passes the idea onto members of his team in the form of his git repo. The readme.md file includes links to relevant reading and his initial thoughts about the system and its design. The code conveys ideas more clearly and compactly than a natural language description would. Even if his team decides to use none of the code -- and he expects they won't -- they start from something more expressive than a plain text document.

This isn't quite a prototype or a spike, but it has the same spirit. The code sketch is another variation on how programming is a medium for expressing ideas in a way that other media can't fully capture.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

July 06, 2015 4:48 PM

Echoes: Aligning Expectations with Reality

Adam Bosworth, in Say No:

Have you ever been busy for an entire week and felt like you got nothing meaningful done? Either your expectations are off or your priorities are.

Brent Simmons, in Love:

If there's a way out of despair, it's in changing our expectations.

Good advice from two people who have been in the trenches for a while.


Posted by Eugene Wallingford | Permalink | Categories: General, Software Development

June 30, 2015 2:39 PM

Software Patterns Are Still For Humans

I recently found myself reading a few of Gregor Hohpe's blog posts and came across Design Patterns: More Than Meets The Eye. In it, Hohpe repeats a message that needs to be repeated every so often even now, twenty years after the publication of the GoF book: software patterns are fundamentally about human communication:

The primary purpose of patterns is to help humans understand design problems. Solving design problems is generally much more difficult than typing in some code, so patterns have enormous value in themselves. Patterns owe their popularity to this value. A better hammer can help speed up the construction of a bed, but a pattern helps us place the bed in a way that makes us feel comfortable.

The last sentence of that paragraph is marvelous.

Hohpe published that piece five and a half years ago. People who write or teach software patterns will find themselves telling a similar story and answering questions like the ones that motivated his post all the time. Earlier this year, Avdi Grimm wrote a like-minded piece, Patterns are for People, in which he took his shot at dispelling misunderstandings from colleagues and friends:

There's a meme, originating from certain corners of the Functional side of programming, that "patterns are a language smell". The implication being that "good" languages either already encode the patterns as language features, or they provide the tools to extend the language such that modeling the pattern explicitly isn't needed.

This misses the point on rather a lot of levels.

Design patterns that are akin to hammers for making better code are plentiful and often quite helpful. But we need more software patterns that help us place our beds in ways that increase human comfort.


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

June 14, 2015 9:17 AM

Software Has Its Own Gresham's Law

Let's call it Sustrik's Law, as its creator does:

Well-designed components are easy to replace. Eventually, they will be replaced by ones that are not so easy to replace.

This is a dandy observation of how software tends to get worse over time, in a natural process of bad components replacing good ones. It made me think of Gresham's Law, which I first encountered in my freshman macroeconomics course:

When a government overvalues one type of money and undervalues another, the undervalued money will leave the country or disappear from circulation into hoards, while the overvalued money will flood into circulation.

A more compact form of this law is, "Bad money drives good money out of circulation."

My memory of Gresham's Law focuses more on human behavior than government behavior. If people value gold more than a paper currency, even though the currency denominates a specific amount of gold, then they will use the paper money in transactions and hoard the gold. The government can redenominate the paper currency at any time, but the gold will always be gold. Bad money drives out the good.

In software, bad components drive good components out of a system for different reasons. Programmers don't hoard good components; they are of no particular value when not being using, even in the future. It's simply pragmatic. If a component is hard to replace, then we are less likely to replace it. It will remain a part of the system over time precisely because it's hard to take out. Conversely, a component that is easy to replace is one that we may replace.

We can also think of this in evolutionary terms, as Brian Foote and Joe Yoder did in The Selfish Class: A hard-to-replace component is better adapted for survival than one that is easy to replace. Designing components to be better for programmers may make them less likely to survive in the long term. How is that for the bad driving out the good?

When we look at this from the perspective of the software system itself, Sustrik's Law reminds us that software is subject to a particular kind of entropy, in which well-designed systems with clean interfaces devolve towards big balls of mud (another term coined by Foote and Yoder). Programmers do not yet have a simple formula to predict this entropy, such as Gibbs entropy law for thermodynamic systems, and may never. But then, computer science is still young. There is a lot we don't know.

Ideas about software have so many connections to other disciplines. I rely on many connections to help me think about them, too. Hat tips to Brian Rice for retweeting this tweet about Sustrik's Law, to Jeff Miller for reminding me about "The Selfish Class", and to Henrik Johansson for suggesting the connection to Gibb's formula.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

June 07, 2015 9:26 AM

Agile Moments, Ernest Hemingway Edition

I couldn't help thinking of big visible charts when I read this paragraph in The Paris Review's interview with Ernest Hemingway:

[Hemingway] keeps track of his daily progress -- "so as not to kid myself" -- on a large chart made out of the side of a cardboard packing case and set up against the wall under the nose of a mounted gazelle head. The numbers on the chart showing the daily output of words differ from 450, 575, 462, 1250, back to 512, the higher figures on days [he] puts in extra work so he won't feel guilty spending the following day fishing on the Gulf Stream.

He uses the chart to keep himself honest. Even our greatest writers can delude themselves into thinking they are making enough progress when they aren't. All the more so for those of us who are still learning, whether how to run a marathon, how to write prose, or how to make software. When a group of people are working together, a chart can help the individuals maintain a common, and honest, understanding of how the team is doing.

Oh, and notice Hemingway's technology: the side of a cardboard packing case. No fancy dashboard for this writer who is known for his direct, unadorned style. If you think you need a digital dashboard with toggles, flashing lights, and subviews, you are doing it wrong. The point of the chart is to keep you honest, not give you another thing to do when you are not doing what you should be doing.

There is another lesson in this passage beyond the chart, about sustainable pace. Most of the numbers are in the ballpark of 500 (average: 499 3/4!), except for one day when he put in a double day. Perhaps 500 words a day is a pace that Hemingway finds productive over time. Yet he allows himself an occasional bit of overtime -- for something important, like time away from his writing desk, out on the water. Many of us programmers need to be reminded every so often that getting away from our work is valuable, and worth an occasional 0 on the big visible chart. It's also a more human motivation for overtime than the mad rush to a release date.

A few pages later in the interview, we read Hemingway repeating a common adage among writers that also echoes nicely against the agile practices:

You read what you have written and, as you always stop when you know what is going to happen next, you go on from there.

Hemingway stops each day at a point where the story will pull him forward the next morning. In this, XP devotees can recognize the habit of ending each day with a broken test. In the morning, or whenever we next fire up our editors, the broken test tells us exactly where to begin and gives us a concrete goal. By the time the test passes, our minds are ready to move on to something new.

Agility is useful when fighting bulls. Apparently, it helps when writing novels, too.


Posted by Eugene Wallingford | Permalink | Categories: General, Software Development

May 28, 2015 2:11 PM

The Grand Complications of Software

Yesterday, Sean Heber made a suggestion drawn, I imagine, from Apple's foray into the world of watchmaking:

I propose we adopt the watch term "complications" for all software features.

It turns out that, in the world of horology, complication is a technical term:

In horology, the study of clocks and watches, a complication refers to any feature in a timepiece beyond the simple display of hours and minutes. A timepiece indicating only hours and minutes is otherwise known as a simple movement.

I don't know if Heber was writing tongue in cheek, but "complication" is certainly a term that programmers can appreciate. In software, we value functions, classes, modules, and even whole systems that do only one thing but do it well. This is sometimes referred to as the single responsibility principle, which engenders a separation of concerns and leads to software that is easier to modify and maintain. Simple movement is one of the defining elements that make up of the the Unix philosophy:

Write programs that do one thing and do it well. Write programs to work together.

In Unix, there is even a standard interface for simple movements, the text stream, which enables almost trivial little programs to be combined to solve any problem.

Horology's use of "complication" also reminds me of Rich Hickey's adoption of the word complect for talking about software systems. See, for example, his RailsConf 2012 talk, Simplicity Matters. Tools that interleave multiple strands of functionality are inherently less reliable, in addition to being harder to work with, so we should seek to create tools with a single strand.

In order to talk about timekeeping devices that perform several functions, watchmakers specialize their term. Informally, a grand complication is a device that contains at least three complications, with at least one timing complication, one astronomical complication, and one striking complications. It might be instructive to classify in a similar fashion the ways in which programmers typically "complect" their code.

The Wikipedia page for "complication" states explicitly that adding complications to a watch makes it more difficult to "design, create, assemble, and repair". That sounds a lot like how programmers feel about complexity. But the page also gives the sense that fine watchmakers revel in complications and see them as a sign of great achievement. Some watchmakers even glory in the complexity of their timepieces.

It seems that watchmakers have more in common with programmers than you might think. Perhaps Heber is on to something here.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

April 27, 2015 2:33 PM

The Program Is In The Programming

I would rather have too little architecture
than too much because that might interfere
with the truth of what I say.
-- Ivan Turgenev

How can agile approaches to software development create coherent programs? Don't we need a plan, a well-thought-out design to follow closely? Without one, won't we end up with a mess?

Let's turn again to Italo Calvino for some perspective. He is known for novels with intricate structure and acknowledges that, for at least a decade, the "architecture" of his books occupied more of his mind than it should have. Yet his novels never seemed to follow closely any of his advance plans:

I spend a lot of time constructing a book, making outlines that eventually prove to be of no use to me whatsoever. I throw them away. What determines the book is the writing, the material that's actually on the page.

The ultimate architecture of a book comes to life alongside the book itself, hand-in-hand with the writing.

And so it can be with software. Programmers can and should think about what they are building but, in the end, what determines the program is the programming, the material that's actually on the page or in the browser.

Again, we must careful not to take the analogy too far. Programs are often created for external clients with specific technical requirements. Programmers are not usually free, as novelists are, to change the product they are creating. Even so, design is how we make the product, not what it does. Whether it evolves during the course of programming or is specified up-front, the client can receive the product they asked us to make.

Ward Cunningham once gave what is, for me, still the best definition of design:

Design is the thinking you do when you make something.

The most important product of that thinking is not a design document or an architecture. It is the mind that is prepared to make the thing you need to make.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

March 24, 2015 3:40 PM

Some Thoughts on How to Teach Programming Better

In How Stephen King Teaches Writing, Jessica Lahey asks Stephen King why we should teach grammar:

Lahey: You write, "One either absorbs the grammatical principles of one's native language in conversation and in reading or one does not." If this is true, why teach grammar in school at all? Why bother to name the parts?

King: When we name the parts, we take away the mystery and turn writing into a problem that can be solved. I used to tell them that if you could put together a model car or assemble a piece of furniture from directions, you could write a sentence. Reading is the key, though. A kid who grows up hearing "It don't matter to me" can only learn doesn't if he/she reads it over and over again.

There are at least three nice ideas in King's answer.

  • It is helpful to beginners when we can turn writing into a problem that can be solved. Making concrete things out of ideas in our head is hard. When we giving students tools and techniques that help them to create basic sentences, paragraphs, and stories, we make the process of creating a bit more concrete and a bit less scary.

  • A first step in this direction is to give names to the things and ideas students need to think about when writing. We don't want students to memorize the names for their own sake; that's a step in the wrong direction. We simply need to have words for talking about the things we need to talk about -- and think about.

  • Reading is, as the old slogan tells us, fundamental. It helps to build knowledge of vocabulary, grammar, usage, and style in a way that the brain absorbs naturally. It creates habits of thought that are hard to undo later.

All of these are true of teaching programmers, too, in their own way.

  • We need ways to demystify the process and give students concrete steps they can take when they encounter a new problem. The design recipe used in the How to Design Programs approach is a great example. Naming recipes and their steps makes them a part of the vocabulary teachers and students can use to make programming a repeatable, reliable process.

  • I've often had great success by giving names to design and implementation patterns, and having those patterns become part of the vocabulary we use to discuss problems and solutions. I have a category for posts about patterns, and a fair number of those relate to teaching beginners. I wish there were more.

  • Finally, while it may not be practical to have students read a hundred programs before writing their first, we cannot underestimate the importance of students reading code in parallel with learning to write code. Reading lots of good examples is a great way for students to absorb ideas about how to write their own code. It also gives them the raw material they need to ask questions. I've long thought that Clancy's and Linn's work on case studies of programming deserves more attention.

Finding ways to integrate design recipes, patterns, and case studies is an area I'd like to explore more in my own teaching.


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

March 11, 2015 4:15 PM

If Design is Important, Do It All The Time

And you don't have to be in software. In Jonathan Ive and the Future of Apple, Ian Parker describes how the process of developing products at Apple has changed during Ive's tenure.

... design had been "a vertical stripe in the chain of events" in a product's delivery; at Apple, it became "a long horizontal stripe, where design is part of every conversation." This cleared a path for other designers.

By the time the iPhone launched, Ive had become "the hub of the wheel".

The vertical stripe/horizontal stripe image brought to mind Kent Beck's reimagining of the software development cycle in XP. I was thinking the image in my head came from Extreme Programming Explained, but the closest thing to my memory I can find is in his IEEE Computer article, Embracing Change with Extreme Programming:

if it's important, do it all the time

My mental image has time on the x-axis, though, which meshes better with the vertical/horizontal metaphor of Robert Brunner, the designer quoted in the passage above.

design as a thin vertical stripe versus design as a long horizontal stripe

If analysis is important, do it all the time. If design is important, do it all the time. If implementation is important, do it all the time. If testing is important, do it all the time.

Ive and his team have shown that there is value in making design an ongoing part of the process for developing hardware products, too, where "design is part of every conversation". This kind of thinking is not just for software any more.


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

March 10, 2015 4:45 PM

Learning to Program is a Loser's Game

After a long break from playing chess, I recently played a few games at the local club. Playing a couple of games twice in the last two weeks has reminded me that I am very rusty. I've only made two horrible blunders in four games, but I have made many small mistakes, the kind of errors that accumulate over time and make a position hard to defend, even untenable. Having played better in years past, these inaccuracies are irksome.

Still, I managed to win all four games. As I've watched games at the club, I've noticed that most games are won by the player who makes the second-to-last blunder. Most of the players are novices, and they trade mistakes: one player leaves his queen en prise; later, his opponent launches an underprepared attack that loses a rook; then the first player trades pieces and leaves himself with a terrible pawn structure -- and so on, the players trading weak or bad moves until the position is lost for one of them.

My secret thus far has been one part luck, one part simple strategy: winning by not losing.

This experience reminded me of a paper called The Loser's Game, which in 1975 suggested that it was no longer possible for a fund manager to beat market averages over time because most of the information needed to do well was available to everyone. To outperform the market average, a fund manager has to profit from mistakes made by other managers, sufficiently often and by a sufficient margin to sustain a long-term advantage. Charles Ellis, the author, contrasts this with the bull markets of the 1960s. Then, managers made profits based on the specific winning investments they made; in the future, though, the best a manager could hope for was not to make the mistakes that other investors would profit from. Fund management had transformed from being a Winner's Game to a Loser's Game.

the cover of Extraordinary Tennis for the Ordinary Tennis Player

Ellis drew his inspiration from another world, too. Simon Ramo had pointed out the differences between a Winner's Game and a Loser's Game in Extraordinary Tennis for the Ordinary Tennis Player. Professional tennis players, Ramo said, win based on the positive actions they take: unreturnable shots down the baseline, passing shots out of the reach of a player at the net, service aces, and so on. We duffers try to emulate our heroes and fail... We hit our deep shots just beyond the baseline, our passing shots just wide of the sideline, and our killer serves into the net. It turns out that mediocre players win based on the errors they don't make. They keep the ball in play, and eventually their opponents make a mistake and lose the point.

Ramo saw that tennis pros are playing a Winner's Game, and average players are playing a Loser's Game. These are fundamentally different games, which reward different mindsets and different strategies. Ellis saw the same thing in the investing world, but as part of a structural shift: what had once been a Winner's Game was now a Loser's Game, to the consternation of fund managers whose mindset is finding the stocks that will earn them big returns. The safer play now, Ellis says, is to minimize mistakes. (This is good news for us amateurs investors!)

This is the same phenomenon I've been seeing at the chess club recently. The novices there are still playing a Loser's Game, where the greatest reward comes to those who make the fewest and smallest mistakes. That's not very exciting, especially for someone who fancies herself to be Adolf Anderssen or Mikhail Tal in search of an immortal game. The best way to win is to stay alive, making moves that are as sound as possible, and wait for the swashbuckler across the board from you to lose the game.

What does this have to do with learning to program? I think that, in many respects, learning to program is a Loser's Game. Even a seemingly beginner-friendly programming language such as Python has an exacting syntax compared to what beginners are used to. The semantics seem foreign, even opaque. It is easy to make a small mistake that chokes the compiler, which then spews an error message that overwhelms the new programmer. The student struggles to fix the error, only to find another error waiting somewhere else in the code. Or he introduces a new error while eliminating the old one, which makes even debugging seem scary. Over time, this can dishearten even the heartiest beginner.

What is the best way to succeed? As in all Loser's Games, the key is to make fewer mistakes: follow examples closely, pay careful attention to syntactic details, and otherwise not stray too far from what you are reading about and using in class. Another path to success is to make the mistakes smaller and less intimidating: take small steps, test the code frequently, and grow solutions rather than write them all at once. It is no accident that the latter sounds like XP and other agile methods; they help to guard us from the Loser's Game and enable us to make better moves.

Just as playing the Loser's Game in tennis or investing calls for a different mindset, so, too does learning to program. Some beginners seem to grok programming quickly and move on to designing and coding brilliantly, but most of us have to settle in for a period of discipline and growth. It may not be exciting to follow examples closely when we want to forge ahead quickly to big ideas, but the alternative is to take big shots and let the compiler win all the battles.

Unlike tennis and Ellis's view of stock investing, programming offers us hope: Nearly all of us can make the transition from the Loser's Game to the Winner's Game. We are not destined to forever play it safe. With practice and time, we can develop the discipline and skills necessary to making bold, winning moves. We just have to be patient and put time and energy into the process of becoming less mistake-prone. By adopting the mindset needed to succeed in a Loser's Game, we can eventually play the Winner's Game.

I'm not too sure about the phrases "Loser's Game" and "Winner's Game", but I think that this analogy can help novice programmers. I'm thinking of ways that I can use it to help my students survive until they can succeed.


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

February 27, 2015 3:37 PM

Bad Habits and Haphazard Design

With an expressive type system for its teaching
languages, HtDP could avoid this problem to some
extent, but adding such rich types would also take
the fun out of programming.

As we approach the midpoint of the semester, Matthias Felleisen's Turing Is Useless strikes a chord in me. My students have spent the last two months learning a little Racket, a little functional programming, and a little about how to write data-driven recursive programs. Yet bad habits learned in their previous courses, or at least unchecked by what they learned there, have made the task harder for many of them than it needed to be.

The essay's title plays off the Church-Turing thesis, which asserts that all programming languages have the same expressive power. This powerful claim is not good news for students who are learning to program, though:

Pragmatically speaking, the thesis is completely useless at best -- because it provides no guideline whatsoever as to how to construct programs -- and misleading at worst -- because it suggests any program is a good program.

With a Turing-universal language, a clever student can find a way to solve any problem with some program. Even uninspired but persistent students can tinker their way to a program that produces the right answers. Unfortunately, they don't understand that the right answers aren't the point; the right program is. Trolling StackOverflow will get them a program, but too often the students don't understand whether it is a good or bad program in their current situation. It just works.

I have not been as faithful to the HtDP approach this semester as I probably should have been, but I share its desire to help students to design programs systematically. We have looked at design patterns that implement specific strategies, not language features. Each strategy focuses on the definition of the data being processed and the definition of the value being produced. This has great value for me as the instructor, because I can usually see right away why a function isn't working for the student the way he or she intended: they have strayed from the data as defined by the problem.

This is also of great value to some of my students. They want to learn how to program in a reliable way, and having tools that guide their thinking is more important than finding yet another primitive Racket procedure to try. For others, though "garage programming" is good enough; they just want get the job done right now, regardless of which muscles they use. Design is not part of their attitude, and that's a hard habit to break. How use doth breed a habit in a student!

Last semester, I taught intro CS from what Felleisen calls a traditional text. Coupled that experience with my experience so far this semester, I'm thinking a lot these days about how we can help students develop a design-centered attitude at the outset of their undergrad courses. I have several blog entries in draft form about last semester, but one thing that stands out is the extent to which every step in the instruction is driven by the next cool programming construct. Put them all on the table, fiddle around for a while, and you'll make something that works. One conclusion we can draw from the Church-Turing thesis is that this isn't surprising. Unfortunately, odds are any program created this way is not a very good program.

~~~~~

(The sentence near the end that sounds like Shakespeare is. It's from The Two Gentlemen of Verona, with a suitable change in noun.)


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

February 21, 2015 11:11 AM

Matthias, Speak to My Students

I love this answer from Matthias Felleisen on the Racket users mailing list today:

The book emphasizes systematic design. You can solve this specific problem with brute force regular-expression matching in a few lines of code. The question is whether you want to learn to solve problems or copy code from mailing lists and StackOverflow without understanding what's really going on.

Students today aren't much different from the students in the good old days. But the tools and information so readily available to them make it a lot easier for them to indulge their baser urges. In the good old days, we had to work hard to get good grades and not understand what we were doing.


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

January 23, 2015 3:35 PM

Agile Design and Jazz

Anyone interested in thinking about how programmers can design software without mapping its structure out in advance should read Ted Gioia's Jazz: The Aesthetics of Imperfection, which appeared in the Winter 1987 issue of The Hudson Review (Volume 39, Number 4, pages 585-600). It explores in some depth the ways in which jazz, which relies heavily on spur-of-the-moment improvisation and thus embraces imperfection, can still produce musical structure worthy of the term "art".

Gioia's contrast of producing musical form via the blueprint method and the retrospective method will resonate with anyone who has grown a large software system via small additions to, and refactorings of, an evolving code base. This paragraph brings to mind the idea of selecting a first test to pass at random:

Some may feel that the blueprint method is the only method by which an artist can adhere to form. But I believe this judgment to be quite wrong. We can imagine the artist beginning his work with an almost random maneuver, and then adapting his later moves to this initial gambit. For example, the musical improviser may begin his solo with a descending five-note phrase and then see, as he proceeds, that he can use this same five-note phrase in other contexts in the course of his improvisation.

Software is different from jazz performance in at least one way that makes the notion of retrospective form even more compelling. In jazz, the most valuable currency is live performance, and each performance is a new creation. We see something similar in the code kata, where each implementation starts from scratch. But unlike jazz, software can evolve over time. When we nurture the same code base over time, we can both incorporate new features and eliminate imperfections from previous iterations. In this way, software developers can create retrospective designs that both benefit from improvisation and reach stable architectures.

Another interesting connection crossed my mind as I read about the role the recording technology played in the development of jazz. With the invention of the phonograph:

... for the first time sounds could be recorded with the same precision that books achieved in recording words. Few realize how important the existence of the phonograph was to the development of improvised music. Hitherto, the only method of preserving musical ideas was through notation, and here the cumbersome task of writing down parts made any significant preservation of improvisations unfeasible. But with the development of the phonograph, improvised music could take root and develop; improvising musicians who lived thousands of miles apart could keep track of each other's development, and even influence each other without ever having met.

Software has long been a written form, but in the last two decades we have seen an explosion of ways in which programs could be recorded and shared with others. The internet and the web enabled tools such as SourceForge and GitHub, which in turn enabled the growth of communities dedicated to the creation and nurturing of open source software. The software so nurtured has often been the product of many people, created through thousands of improvisations by programmers living in all corners of the world. New programmers come to these repositories, the record stores of our world, and are able to learn from masters by studying their moves and their creations. They are then able to make their own contributions to existing projects, and to create new projects of their own.

As Gioia says of jazz, this is not to make the absurd claim that agile software did not exist before it was recorded and shared in this way, but the web and the public repository have had profound impacts on the way software is created. The retrospective form espoused by agile software design methods, the jazz of our industry, has been one valuable result.

Check out Gioia's article. It repaid my investment with worthy connections. If nothing else, it taught me a lot about jazz and music criticism.


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

December 29, 2014 3:27 PM

Exceptions Should Be Exceptional

Exceptions signal something outside the expected bounds of behavior of the code in question. But if you're running some checks on outside input, this is because you expect some messages to fail -- and if a failure is expected behavior, then you shouldn't be using exceptions.

That is a snippet from Replacing Throwing Exceptions with Notification in Validations, a refactoring Martin Fowler published earlier this month. The refactoring is based on an extraordinarily useful piece of software design advice: exceptions should be unexpected. If something is expected, it's not exceptional. Make your software say so. A notification mechanism can carry as much information about system behavior as exceptions and generally provides superior cohesion and division of labor.

Over the last few years, I've come to see that is really a tenet of good system design more generally. A couple of examples from my university experience:

  • If your curriculum depends on frequent student requests to enable programs of study that faculty accept as reasonable, then you should probably modify the curriculum to allow what is reasonable. Not only are you gumming up the larger system with unnecessary paperwork, you are likely disadvantaging students who aren't savvy or cheeky enough to disregard the rules.

  • If the way you pay for instruction and equipment doesn't match the stated budget, then you should change the budget to reflect reality. If you don't control the writing of the budget, then you should find ways to communicate reality to the budget writers whenever possible. Sometimes, you can work around the given budget to accomplish what you really need for a long time. But over time the system will evolve in response to other external forces, and you reach a point where the budget in no way reflects reality. A sudden change in funding can put you in a state of real crisis. Few people will be able to understand why.

People sometimes tell me that I am naive to think complex systems like a university or even a curriculum should reflect reality closely. Programming has taught me that we almost always benefit from keeping our design as clean, as understandable, and as truthful as we can. I am pragmatic enough to understand that there are exceptions even to this tenet, in life and in software. But exceptions should be exceptional.


Posted by Eugene Wallingford | Permalink | Categories: Managing and Leading, Software Development

December 18, 2014 2:33 PM

Technical Problems Are The Easy Ones

Perhaps amid the daily tribulations of a software project, Steven Baker writes

Oy. A moving goal line, with a skeleton crew, on a shoestring budget. Technical problems are the easy ones.

And here we all sit complaining about monads and Java web frameworks...

My big project this semester has not been developing software but teaching beginners to develop software, in our intro course. There is more to Intro than programming, but for many students the tasks of learning a language and trying to write programs comes to dominate most everything else. More on that soon.

Yet even with this different sort of project, I feel much as Baker does. Freshmen have a lot of habits to learn and un-learn, habits that go well beyond how they do Python. My course competes with several others for the students' attention, not to mention with their jobs and their lives outside of school. They come to class with a lifetime of experience and knowledge, as well some surprising gaps in what they know. A few are a little scared by college, and many worry that CS won't be a good fit for them.

The technical problems really are the easy ones.


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

December 01, 2014 2:05 PM

When YAGNI Becomes "Now We Need It"

The Codist told the story of DeltaGraph last week. It must be quite a feeling to have code you wrote twenty-five years ago still running in a commercial product today. Of course, such longevity creates challenges for the maintainers. The longer a program lives, the more likely that a feature that you thought you'd never need becomes desirable, even necessary.

Like a Windows version, circa 1989:

When I started the UI code I asked two questions of Deltapoint (1) will this code ever be ported to Windows (2) do you want to support multiple documents open at a time. The answer to both was no. Windows was still too primitive to care about and multiple open documents was fairly uncommon.

Within a few years, "You Aren't Gonna Need It" turned into "Now We Need It":

With 3.0 they actually began to port it to Windows 3.1, and it was an immense pain to do. I had spent no time trying to worry about cross platform issues as I had asked up front and been told no. Of course Windows was now becoming important. The port was never very stable as a result and I think it actually became a separate code base, making new features hard to do.

This is one of the balancing essential acts of writing software. Operating with a YAGNI mindset is generally a prudent way to ensure we don't write code that is unnecessarily complex and hard to work with. Yet we have to make our programs open to the changes that will inevitably follow. And some changes are easier to make if we have built hooks and fulcrums into the code.

So, we strive for ways not to build the things we don't need now, but make it possible to accommodate them later. For me, this has always been the great promise of object-oriented programming. I try to think that way even when I'm working in languages that don't support the style directly, but I'm not good enough yet. That only helps me admire the accomplishments of teams like the one that created DeltaGraph even more.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

November 20, 2014 3:23 PM

When I Procrastinate, I Write Code

I procrastinated one day with my intro students in mind. This is the bedtime story I told them as a result. Yes, I know that I can write shorter Python code to do this. They are intro students, after all.

~~~~~

Once upon a time, a buddy of mine, Chad, sent out a tweet. Chad is a physics prof, and he was procrastinating. How many people would I need to have in class, he wondered, to have a 50-50 chance that my class roster will contain people whose last names start with every letter of the alphabet?

    Adams
    Brown
    Connor
    ...
    Young
    Zielinski

This is a lot like the old trivia about how we only need to have 23 people in the room to have a 50-50 chance that two people share a birthday. The math for calculating that is straightforward enough, once you know it. But last names are much more unevenly distributed across the alphabet than birthdays are across the days of the year. To do this right, we need to know rough percentages for each letter of the alphabet.

I can procrastinate, too. So I surfed over to the US Census Bureau, rummaged around for a while, and finally found a page on Frequently Occurring Surnames from the Census 2000. It provides a little summary information and then links to a couple of data files, including a spreadsheet of data on all surnames that occurred at least 100 times in the 2000 census. This should, I figure, cover enough of the US population to give us a reasonable picture of how peoples' last names are distributed across the alphabet. So I grabbed it.

(We live in a wonderful time. Between open government, open research, and open source projects, we have access to so much cool data!)

The spreadsheet has columns with these headers:

    name,rank,count,prop100k,cum_prop100k,      \
                    pctwhite,pctblack,pctapi,   \
                    pctaian,pct2prace,pcthispanic

The first and third columns are what we want. After thirteen weeks, we know how to do compute the percentages we need: Use the running total pattern to count the number of people whose name starts with 'a', 'b', ..., 'z', as well as how many people there are altogether. Then loop through our collection of letter counts and compute the percentages.

Now, how should we represent the data in our program? We need twenty-six counters for the letter counts, and one more for the overall total. We could make twenty-seven unique variables, but then our program would be so-o-o-o-o-o long, and tedious to write. We can do better.

For the letter counts, we might use a list, where slot 0 holds a's count, slot 1 holds b's count, and so one, through slot 25, which holds z's count. But then we would have to translate letters into slots, and back, which would make our code harder to write. It would also make our data harder to inspect directly.

    ----  ----  ----  ...  ----  ----  ----    slots in the list

0 1 2 ... 23 24 25 indices into the list

The downside of this approach is that lists are indexed by integer values, while we are working with letters. Python has another kind of data structure that solves just this problem, the dictionary. A dictionary maps keys onto values. The keys and values can be of just about any data type. What we want to do is map letters (characters) onto numbers of people (integers):

    ----  ----  ----  ...  ----  ----  ----    slots in the dictionary

'a' 'b' 'c' ... 'x' 'y' 'z' indices into the dictionary

With this new tool in hand, we are ready to solve our problem. First, we build a dictionary of counters, initialized to 0.

    count_all_names = 0
    total_names = {}
    for letter in 'abcdefghijklmnopqrstuvwxyz':
        total_names[letter] = 0

(Note two bits of syntax here. We use {} for dictionary literals, and we use the familiar [] for accessing entries in the dictionary.)

Next, we loop through the file and update the running total for corresponding letter, as well as the counter of all names.

    source = open('app_c.csv', 'r')
    for entry in source:
        field  = entry.split(',')        # split the line
        name   = field[0].lower()        # pull out lowercase name
        letter = name[0]                 # grab its first character
        count  = int( field[2] )         # pull out number of people
        total_names[letter] += count     # update letter counter
        count_all_names     += count     # update global counter
    source.close()

Finally, we print the letter → count pairs.

    for (letter, count_for_letter) in total_names.items():
        print(letter, '->', count_for_letter/count_all_names)

(Note the items method for dictionaries. It returns a collection of key/value tuples. Recall that tuples are simply immutable lists.)

We have converted the data file into the percentages we need.

    q -> 0.002206197888442366
    c -> 0.07694634659082318
    h -> 0.0726864447688946
    ...
    f -> 0.03450702533438715
    x -> 0.0002412718532764804
    k -> 0.03294646311104032

(The entries are not printed in alphabetical order. Can you find out why?)

I dumped the output to a text file and used Unix's built-in sort to create my final result. I tweet Chad, Here are your percentages. You do the math.

Hey, I'm a programmer. When I procrastinate, I write code.


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

November 07, 2014 2:12 PM

Three Students, Three Questions

In the lab, Student 1 asks a question about the loop variable on a Python for statement. My first thought is, "How can you not know that? We are in Week 11." I answer, he asks another question, and we talk some more. The conversation shows me that he has understood some ideas at a deeper level, but a little piece was missing. His question helped him build a more complete and accurate model of how programs work.

Before class, Student 2 asks a question about our current programming assignment. My first thought is, "Have you read the assignment? It answers your question." I answer, he asks another question, and we talk some more. The conversation shows me that he is thinking carefully about details of the assignment, but assignments at this level of detail are new to him. His question helped him learn a bit more about how to read a specification.

After class, Student 3 asks a question about our previous programming assignment. We had recently looked at my solution to the assignment and discussed design issues. "Your program is so clean and organized. My program is so ugly. How can I write better-looking programs?" He is already one of the better students in the course. We discuss the role of experience in writing clearly, and I explain that the best programs are often the result of revision and refactoring. They started out just good enough, and the author worked to make them better. The conversation shows me that he cares about the quality of his code, that elegance matters as much to him as correctness. His question keeps him moving along the path to becoming a good programmer.

Three students, three questions: all three are signs of good things to come. They also remind me that even questions which seem backward at first can point forward.


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

October 24, 2014 3:05 PM

It's Blueprints All The Way Down

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:

  • designing software, and thinking about how this will play out code, and
  • writing code, and thinking about how this affects the design of the system.

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.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

October 21, 2014 3:13 PM

Ernest Hemingway, Programmer

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.


Posted by Eugene Wallingford | Permalink | Categories: General, Software Development

October 17, 2014 3:05 PM

Assorted Quotes

... 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.

On the evolution of software. Nat Pryce on the Twitter, via The Problematic Culture of "Worse is Better":

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.


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

October 16, 2014 3:54 PM

For Programmers, There Is No "Normal Person" Feeling

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.


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

October 06, 2014 4:02 PM

A New Programming Language Can Inspire Us

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:

  • Programmers are often most inspired when a language shows them new ideas how to solve problems.
  • Even if we love a language, we won't necessarily love every feature of the language.
  • What inspires us is personal. Other people can be inspired by languages that do not excite us.
  • Community matters.

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.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

October 02, 2014 3:46 PM

Skills We Can Learn

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.


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

September 25, 2014 4:18 PM

Producers and Consumers

The more you produce and the more needs you meet, the more freedom you earn.

As Seth Godin says, it's fun to be (only) a consumer, but in the long run, smart producers win. Knowing how to produce solutions for yourself and others is the first step to freedom. Actually making things is the second.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

September 24, 2014 3:54 PM

Is It Really That Hard?

This morning, I tweeted:

Pretty sure I could build a git-based curriculum management system in two weeks that would be miles better than anything on the market now.

Yes, I know that it is easy to have ideas, and that carrying an idea through to a product is the real challenge. At least I don't just need a programmer...

My tweet was the result of temporary madness provoked by yet another round of listening to non-CS colleagues talk about one of the pieces of software we use on campus. It is a commercial product purchased for one task only, to help us manage the cycle of updating the university catalog. Alas, in its current state, it can handle only one catalog at a time. This is, of course, inconvenient. There are always at least two catalogs: the one in effect at this moment, and the one in progress of being updated. That doesn't even take into account all of the old catalogs still in effect for the students who entered the university when they were The Catalog.

Yes, we need version control. Either the current software does not provide it, or that feature is turned off.

The madness arises because of the deep internal conflict that occurs within me when I'm drawn into such conversations. Everyone assumes that programs "can't do this", or that the programmers who wrote our product were mean or incompetent. I could try to convince them otherwise by explaining the idea of version control. But their experience with commercial software is so uniformly bad that they have a hard time imagining I'm telling the truth. Either I misunderstand the problem, or I am telling them a white lie.

The alternative is to shake my head, agree with them implicitly, and keep thinking about how to teach my intro students how to design simple programs.

I'm convinced that a suitable web front-end to a git back end could do 98% of what we need, which is about 53% more than either of our last two commercial solutions has done for us.

Maybe it's time for me to take a leave of absence, put together a small team of programmers, and do this. Yes, I would need a team. I know my limitations, and besides working with a few friends would be a lot more fun. The current tools in this space leave a lot of room for improvement. Built well and marketed well, this product would make enough money from satisfaction-starved universities to reward everyone on the team well enough for all to retire comfortably.

Maybe not. But the idea is free the taking. All I ask is that if you build it, give me a shout-out on your website. Oh, and cut my university a good deal when we buy your software to replace whatever product we are grumbling about when you reach market.


Posted by Eugene Wallingford | Permalink | Categories: General, Software Development

September 19, 2014 3:34 PM

Ask Yourself, "What is the Pattern?"

I ran across this paragraph in an essay about things you really need to learn in college:

Indeed, you should view the study of mathematics, history, science, and mechanics as the study of archetypes, basic patterns that you will recognize over and over. But this means that, when you study these disciplines, you should be asking, "what is the pattern" (and not merely "what are the facts"). And asking this question will actually make these disciplines easier to learn.

Even in our intro course, I try to help students develop this habit. Rather than spending all of our time looking at syntax and a laundry list of language features, I am introducing them to some of the most basic code patterns, structures they will encounter repeatedly as they solve problems at this level. In week one came Input-Process-Output. Then after learning basic control structures, we encountered guarded actions, range tests, running totals, sentinel loops, and "loop and a half". We encounter these patterns in the process of solving problems.

While they are quite low-level, they are not merely idioms. They are patterns every bit as much as patterns at the level of the Gang of Four or PoSA. They solve common problems, recur in many forms, and are subject to trade-offs that depend on the specific problem instance.

They compose nicely to create larger programs. One of my goals for next week is to have students solve new problems that allow them to assemble programs from ideas they have already seen. No new syntax or language features, just new problems.


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

July 17, 2014 10:00 AM

A New Commandment

... I give unto you:

Our first reaction to any comrade, any other person passionate about and interested in building things with computers, any human crazy and masochistic enough to try to expand the capabilities of these absurd machines, should be empathy and love.

Courtesy of Britt Butler.

I hope to impart such empathy and love to my intro students this fall. Love to program, and be part of a community that loves and learns together.


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

July 03, 2014 2:13 PM

Agile Moments: Conspicuous Progress and Partial Value

Dorian Taylor, in Toward a Theory of Design as Computation:

You can scarcely compress the time it takes to do good design. The best you can do is arrange the process so that progress is conspicuous and the partially-completed result has its own intrinsic value.

Taylor's piece is about an idea much bigger than simply software methodology, but this passage leapt off the page at me. It seems to embody two of the highest goals of the various agile approaches to making software: progress that is conspicuous and partial results that have intrinsic value to the user.

If you like ambition attempts to create a philosophy of design, check out the whole essay. Taylor connects several disparate sources:

  • Edwin Hutchins and Cognition in the Wild,
  • Donald Norman and Things That Make Us Smart, and
  • Douglas Hofstadter and Gödel, Escher, Bach
with the philosophy of Christopher Alexander, in particular Notes on the Synthesis of Form and The Nature of Order. Ambitious it is.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

July 02, 2014 4:31 PM

My Jacket Blurb for "Exercises in Programming Style"

On Monday, my copy of Crista Lopes's new book, Exercises in Programming Style, arrived. After blogging about the book last year, Crista asked me to review some early chapters. After I did that, the publisher graciously offered me a courtesy copy. I'm glad it did! The book goes well beyond Crista's talk at StrangeLoop last fall, with thirty three styles grouped loosely into nine categories. Each chapter includes historical notes and a reading list for going deeper. Readers of this blog know that I often like to go deeper.

I haven't had a chance to study any of the chapters deeply yet, so I don't have a detailed review. For now, let me share the blurb I wrote for the back cover. It gives a sense of why I was so excited by the chapters I reviewed last summer and by Crista's talk last fall:

It is difficult to appreciate a programming style until you see it in action. Cristina's book does something amazing: it shows us dozens of styles in action on the same program. The program itself is simple. The result, though, is a deeper understanding of how thinking differently about a problem gives rise to very different programs. This book not only introduced me to several new styles of thinking; it also taught me something new about the styles I already know well and use every day.

The best way to appreciate a style is to use it yourself. I think Crista's book opens the door for many programmers to do just that with many styles most of us don't use very often.

As for the blurb itself: it sounds a little stilted as I read it now, but I stand by the sentiment. It is very cool to see my blurb and name along side blurbs from James Noble and Grady Booch, two people whose work I respect so much. Very cool. Leave it to James to sum up his thoughts in a sentence!

While you are waiting for your copy of Crista's book to arrive, check out her recent blog entry on the evolution of CS papers in publication over the last 50+ years. It presents a lot of great information, with some nice images of pages from a few classics. It's worth a read.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

June 20, 2014 1:27 PM

Programming Everywhere, Business Edition

Q: What do you call a company that has staff members with "programmer" or "software developer" in their titles?

A: A company.

Back in 2012, Alex Payne wrote What Is and Is Not A Technology Company to address a variety of issues related to the confounding of companies that sell technology with companies that merely use technology to sell something else. Even then, developing technology in house was a potential source of competitive advantage for many businesses, whether that involved modifying existing software or writing new.

The competitive value in being able to adapt and create software is only larger and more significant in the last two years. Not having someone on staff with "programmer" in the title is almost a red flag even for non-tech companies these days.

Those programmers aren't likely to have been CS majors in college, though. We don't produce enough. So we need to find a way to convince more non-majors to learn a little programming.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

June 12, 2014 2:29 PM

Points of Emphasis for Teaching Design

As I mentioned recently, design skills were a limiting factor for some of the students in my May term course on agile software development. I saw similar issues for many in my spring Algorithms course as well. Implementing an algorithm from lecture or reading was straightforward enough, but organizing the code of the larger system in which the algorithm resided often created challenges for students.

I've been thinking about ways to improve how I teach design in the future, both in courses where design is a focus and in courses where it lives in the background of other material. Anything I come up with can be also part of conversation with colleagues as we talk about design in their courses.

I read Kent Beck's initial Responsive Design article when it first came out a few years ago and blogged about it then, because it had so many useful ideas for me and my students. I decided to re-read the article again last week, looking for a booster shot of inspiration.

First off, it was nice to remember how many of the techniques and ideas that Kent mentions already play a big role in my courses. Ones that stood out on this reading included:

  • taking safe steps,
  • isolating changes within modules,
  • recognizing that design is a team sport, fundamentally a social activity, and
  • playing with words and pictures.

My recent experiences in the classroom made two other items in Kent's list stand out as things I'll probably emphasize more, or at least differently, in upcoming courses.

Exploit Symmetries. Divide similar elements into identical parts and different parts.

As I noted in my first blog about this article, many programmers find it counterintuitive to use duplication as a tool in design. My students struggle with this, too. Soon after that blog entry, I described an example of increasing duplication in order to eliminate duplication in a course. A few years later, in a fit of deja vu, I wrote about another example, in which code duplication is a hint to think differently about a problem.

I am going to look for more opportunities to help students see ways in which they can make design better by isolating code into the identical and the different.

Inside or Outside. Change the interface or the implementation but not both at the same time.

This is one of the fundamental tenets of design, something students should learn as early as possible. I was surprised to see how normal it was for students in my agile development course not to follow this pattern, even when it quickly got them into trouble. When you try to refactor interface and implementation at the same time, things usually don't go well. That's not a safe step to take...

My students and I discussed writing unit tests before writing code a lot during the course. Only afterward did it occur to me that Inside or Outside is the basic element of test-first programming and TDD. First, we write the test; this is where we design the interface of our system. Then, we write code to pass the test; this is where we implement the system.

Again, in upcoming courses, I am going to look for opportunities to help students think more effectively about the distinction between the inside and the outside of their code.

Thus, I have a couple of ideas for the future. Hurray! Even so, I'm not sure how I feel about my blog entry of four years ago. I had the good sense to read Kent's article back then, draw some good ideas from it, and write a blog entry about them. That's good. But here I am four years later, and I still feel like I need to make the same sort of improvements to how I teach.

In the end, I am glad I wrote that blog entry four years ago. Reading it now reminds me of thoughts I forgot long ago, and reminds me to aim higher. My opening reference to getting a booster shot seems like a useful analogy for talking about this situation in my teaching.


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

June 07, 2014 10:17 AM

Pascal, Forgiveness, and CS1

Last time, I thought about the the role of forgiveness in selecting programming languages for instruction. I mentioned that BASIC had worked well for me as a first programming language, as it had worked for so many others. Yet I would probably would never choose it as a language for CS1, at least for more than a few weeks of instruction. It is missing a lot of the features that we want CS majors to learn about early. It's also a bit too free.

In that post, I did say that I still consider Pascal a good standard for first languages. It dominated CS1 for a couple of decades. What made it work so well as a first instructional language?

Pascal struck a nice balance for its time. It was small enough that students could master it all, and also provided constructs for structured programming. It had the sort of syntax that enabled a compiler to provide students guidance about errors, but its compilers did not seem overbearing. It had a few "gothchas", such as the ; as a statement separator, but not so many that students were constantly perplexed. (Hey to C++.) Students were able try things out and get programs to work without becoming demoralized by a seemingly endless stream of complaints.

(Aside: I have to admit that I liked Pascal's ; statement separator. I understood it conceptually and, in a strange way, appreciated it aesthetically. Most others seem to have disagreed with me...)

Python has attracted a lot of interest as a CS1 language in recent years. It's the first popular language in a long while that brings to mind Pascal's feel for me. However, Pascal had two things that supported the teaching of CS majors that Python does not: manifest types and pointers. I love dynamically-typed languages with managed memory and prefer them for my own work, but using that sort of language in CS1 creates some new challenges when preparing students for upper-division majors courses.

So, Pascal holds a special place for me as a CS1 language, though it was not the language I learned there. We used it to teach CS1 for many years and it served me and our students well. I think it balances a good level of forgiveness with a reasonable level of structure, all in a relatively small package.


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

June 06, 2014 4:24 PM

Programming Languages and the Right Level of Forgiveness

In the last session of my May term course on agile software development, discussion eventually turned to tools and programming languages. We talked about whether some languages are more suited to agile development than others, and whether some languages are better tools for a given developer team at a given time. Students being students, we also discussed the courses used in CS courses, including the intro course.

Having recently thought some about choosing the right languages for early CS instruction, I was interested to hear what students thought. Haskell and Scala came up; they are the current pet languages of students in the course. So did Python, Java, and Ada, which are languages our students have seen in their first-year courses. I was the old guy in the room, so I mentioned Pascal, which I still consider a good standard for comparing CS1 languages, and classic Basic, which so many programmers of my generation and earlier learned as their first exposure to the magic of making computers do our bidding.

Somewhere in the conversation, an interesting idea came up regarding the first language that people learn: good first languages provide the right amount of forgiveness when programmers make mistakes.

A language that is too forgiving will allow the learner to be sloppy and fall into bad habits.

A language that is not forgiving enough can leave students dispirited under a barrage of not good enough, a barrage of type errors and syntax gotchas.

What we mean by 'forgiving' is hard to define. For this and other reasons, not everyone agrees with this claim.

Even when people agree in principle with this idea, they often have a hard time agreeing on where to draw the line between too forgiving and not forgiving enough. As with so many design decisions, the correct answer is likely a local maximum that balances the forces at play among the teachers, students, and desired applications involved.

I found Basic to be just right. It gave me freedom to play, to quickly make interesting programs run, and to learn from programs that didn't do what I expected. For many people's taste, though Basic is too forgiving and leads to diseased minds. (Hey to Edsger Dijkstra.) Maybe I was fortunate to learn how to use GOSUBs early and well.

Haskell seems like a language that would be too unforgiving for most learners. Then again, neither my students nor I have experience with it as a first-year language, so maybe we are wrong. We could imagine ways in which learning it first would lead to useful habits of thought about types and problem decomposition. We are aware of schools that use Haskell in CS1; perhaps they have made it work for them. Still, it feels a little too judgmental...

In the end, you can't overlook context and the value of good tools. Maybe these things shift the line of "just right" forgiveness for different audiences. In any case, finding the right level seems to be a useful consideration in choosing a language.

I suspect this is true when choosing languages to work in professionally, too.


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

May 30, 2014 4:09 PM

Programming is Social

The February 2014 issue of Math Horizons included A Conversation With Steven Strogatz, an interview conducted by Patrick Honner. The following passage came to mind this week:

PH: Math is collaborative?

SS: Yeah, math is social. ... The fact that math is social would come as a surprise to the people who think of it as antisocial.

PH: It might also come as a surprise to some math teachers!

SS: It's extremely social. Mathematicians constantly spend time talking to each other about places where they're stuck. They get insights from each other, new ways of looking at things. Sometimes it's just to commiserate.

Programming is social, too. Most people think it's not. With assistance from media portrayals of programmers and sloppy stereotypes of our own, they think most of us would prefer to work alone in the dark. Some do, of course, but even then most programmers I know like to talk shop with other programmers all the time. They like to talk about the places where they are stuck, as well as the places they used to be stuck. War stories are the currency of the programmer community.

I think a big chunk of the "programming solo" preference many programmers profess is learned habit. Most programming instruction and university course work encourages or requires students to work alone. What if we started students off with pair programming in their CS 1 course, and other courses nurtured that habit throughout the rest of their studies? Perhaps programmers would learn a different habit.

My agile software development students this semester are doing all of their project work via pair programming. Class time is full of discussion: about the problem they are solving, about the program they are evolving, and about the intricacies of Java. They've been learning something about all three, and a large part of that learning has been social.

They've only been trying out XP for a couple of weeks, so naturally the new style hasn't replaced their old habits. I see them fall out of pairing occasionally. One partner will switch off to another computer to look up the documentation for a Java class, and pretty soon both partners are quietly looking at their own screens. Out of deference to me or the course, though, they return after a couple of minutes and resume their conversation. (I'm trying to be a gentle coach, not a ruthless tyrant, when it comes to the practices.)

I suspect a couple members of the class would prefer to program on their own, even after noticing the benefits of pairing. Others really enjoy pair programming but may well fall back into solo programming after the class ends. Old habits die hard, if at all. That's too bad, because most of us are better programmers when pairing.

But even if they do choose, or fall back into, old habits, I'm sure that programming will remain a social activity for them, at some level. There are too many war stories to tell.


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

May 23, 2014 12:27 PM

Words Matter, Even in Code

Jim Weirich on dealing with failure in Ruby, via Avdi Grimm's blog:

(An aside, because I use exceptions to indicate failures, I almost always use the "fail" keyword rather than the "raise" keyword in Ruby. Fail and raise are synonyms so there is no difference except that "fail" more clearly communicates that the method has failed. The only time I use "raise" is when I am catching an exception and re-raising it, because here I'm *not* failing, but explicitly and purposefully raising an exception. This is a stylistic issue I follow, but I doubt many other people do).

Words matter: the right words, used at the right times. Weirich always cared about words, and it showed both in his code and in his teaching and writing.

The students in my agile class got to see my obsession with word choice and phrasing in class yesterday, when we worked through the story cards they had written for their project. I asked questions about many of their stories, trying to help them express what they intended as clearly as possible. Occasionally, I asked, "How will you write the test for this?" In their proposed test we found what they really meant and were able to rephrase the story.

Writing stories is hard, even for experienced programmers. My students are doing this for the first time, and they seemed to appreciate the need to spend time thinking about their stories and looking for ways to make them better. Of course, we've already discussed the importance of good names, and they've already experienced that way in which words matter in their own code.

Whenever I hear someone say that oral and verbal communication skills aren't all that important for becoming a good programmer, I try to help them see that they are, and why. Almost always, I find that they are not programmers and are just assuming that we techies spend all our time living inside mathematical computer languages. If they had ever written much software, they'd already know.


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

May 19, 2014 4:09 PM

Becoming More Agile in Class, No. 2

After spending a couple of days becoming familiar with pair programming and unit tests, for Day 4 we moved on to the next step: refactoring. I had the students study the "before" code base from Martin Fowler's book, Refactoring, to identify several ways they thought we could improve it. Then they worked in pairs to implement their ideas. The code itself is pretty simple -- a small part of the information system for a movie rental store -- and let the students focus on practice with tools, running tests, and keeping the code base "green".

We all know Fowler's canonical definition of refactoring:

Refactoring is the process of changing a software system in such a way that it does not alter the external behavior of the code yet improves its internal structure.

... but it's easy to forget that refactoring really is about design. Programmers with limited experience in Java or OOP can bring only so much to the conversation about improving an OO program written in Java. We can refactor confidently and well only if we have a target in mind, one we understand and can envision in our code. Further, creating a good software design requires taste, and taste generally comes from experience.

I noticed this lack of experience manifesting itself in the way my students tried to decompose the work of a refactoring into small, safe steps. When we struggle with decomposing a refactoring, we naturally struggle with choosing the next step to work on. Kent Beck calls this the challenge of succession. Ordering the steps of a refactoring is a more subtle challenge than many programmers realize at first.

This session reminded me why I like to teach design and refactoring in parallel: coming to appreciate new code smells and quickly learning how to refactor code into a better state. This way, programming skill grows along side the design skill.

On Day 5, we tried to put the skills from the three previous days all together, using an XP-style test-code-refactor-repeat cycle to implement a bit of code. Students worked on either the Checkout kata from Dave Thomas or a tic-tac-toe game based on a write-up by Gojko Adzic. No, these are not the most exciting programs to build, but as I told the class, this makes it possible for them to focus on the XP practices and habits of mind -- small steps, unit tests, and refactoring -- without having to work too hard to grok the domain.

My initial impression as the students worked was that the exercise wasn't going as well as I had hoped it would. The step size was too big, and the tests were too intrusive, and the refactoring was almost non-existent. Afterwards, though, I realized that programmers learning such foreign new habits must go through this phase. The best I can do is inject an occasional suggestion or question, hoping that it helps speed them along the curve.

This morning, I decided to have each student pair up with someone who had worked on the other task last time, flip a coin, and work on the one of the same two tasks. This way, each pair had someone working on the same problem again and someone working on a new problem. I instructed them to start from scratch -- new code, new thoughts -- and have the person new to the task write the first test.

The goal wass to create an asymmetry within each pair. Working on the same piece again would be valuable for the partner doing so, in the way playing finger exercises or etudes is valuable for a musician. At the same time, the other partner would see a new problem, bringing fresh eyes and thoughts to the exercise. This approach seems like a good one, as it varies the experience for both members of the pair. I know how important varying the environment can be for student learning, but I sometimes forget to do that often enough in class.

The results seemed so much better today. Students commented that they made better progress this time around, not because one of them had worked on the same problem last time, but because they were feeling more comfortable with the XP practices. One students something to the effect,

Last time, we were trying to work on the simplest or smallest piece of code we could write. This time, we were trying to work on the smallest piece of functionality we could add to the program.

That's a solid insight from an undergrad, even one with a couple of years programming experience.

I also liked the conversation I was hearing among the pairs. They asked each other, "Should we do this feature next, or this other?" and said, "I'm not sure how we can test this." -- and then talked it over before proceeding. One pair had a wider disparity in OO experience, so the more experienced programmer was thinking out loud as he drove, taking into account comments from his partner as he coded.

This is a good sign. I'm under no illusion that they have all suddenly mastered ordering features, writing unit tests, or refactoring. We'll hit bumps over the next three weeks. But they all seem to be pretty comfortable with working together and collaborating on code. That's an essential skill on an agile team.

Next up: the Planning Game for a project that we'll work on for the rest of the class. They chose their own system to build, a cool little Android game app. That will change the dynamic a bit for customer collaboration and story writing, but I think that the increased desire to see a finished product will increase their motivation to master the skills and practice. My job as part-time customer, part-time coach will require extra vigilance to keep them on track.


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

May 14, 2014 4:52 PM

Becoming More Agile in Class

Days 2 and 3 of my Agile Software Development May term course are now in the books. This year, I decided to move as quickly as we could in the lab. Yesterday, the students did their first pair-programming session, working for a little over an hour on one of the industry standard exercises, Conway's Game of Life. Today, they did their first pair programming with unit tests, using Bill Wake's Test-First Challenge to implement the beginnings of a simple data model for spreadsheets.

I always enjoy watching students write code and interacting with them while they do it. The thing that jumped out to me yesterday was just how much code some students write before they ever think about compiling it, let alone testing it. Another was how some students manage to get through a year of programming-heavy CS courses without mastering their basic tools: text editor, compiler, and language. It's hard to work confidently when your tools feel uncomfortable in your hands.

There's not much I can do to help students develop greater facility with their tools than give them lots of practice, and we will do that. However, writing too much code before testing even its syntactic correctness is a matter of mindset and habit. So I opened today's session with a brief discussion, and then showed them what I meant in the form of a short bit of code I wrote yesterday while watching them. Then I turned them loose with Wake's spreadsheet tests and encouragement to help each other write simple code, compile frequently even with short snippets, and run the tests as often as their code compiles.

Today, we had an odd number of students in class, something that's likely to be our standard condition this term, so paired with one of the students on a spreadsheet. He wanted to work in Haskell, and I was game. I refreshed my Haskell memories a bit and even contributed some helpful bits of code, in addition to meta-contributions on XP style.

The student is relatively new to the language, so he's still developing the Haskell in his in his mind. There were times we struggled because we were thinking of the problem in a stateful way. As you surely know, that's not the best way to work in Haskell. Our solutions were not always elegant, but we did our best to get in the rhythm of writing tests, writing code, and running.

As the period was coming to an end, our code had just passed a test that had been challenging us. Almost simultaneously, a student in another thrust his arms in the air as his pair's code passed a challenging test, too, much deeper in the suite. We all decided to declare victory and move on. We'll all get better with practice.

Next up: refactoring, and tools to support it and automated testing.


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

May 12, 2014 5:01 PM

Teaching a Compressed Class

May term started today, so my agile course is off the ground. We will meet for 130 minutes every morning through June 6, excepting only Memorial Day. That's a lot of time spent together in a short period of time.

As I told the students today, each class is almost a week's worth of class in a regular semester. This means committing a fair amount of time out of class every day, on the order of 5-7 hours. There isn't a lot of time for our brains to percolate on the course content. We'll be moving steadily for four weeks.

This makes May term unsuitable, in my mind at least, for a number of courses. I would never teach CS 1 in May term. Students are brand new to the discipline, to programming, and usually to their first programming language. They need time for the brains to percolate. I don't think I'd want to teach upper-division CS courses in May term if they have a lot of content, either. Our brains don't always absorb a lot of information quickly in a short amount of time, so letting it sink in more slowly, helped by practice and repetition, seems best.

My agile course is, on the other hand, almost custom made for a compressed semester. There isn't a lot of essential "content". The idea is straightforward. I don't expect students to memorize lists of practices, or the rules of tools. I expect them to do the practices. Doing them daily, in extended chunks of time, with immediate feedback, is much better than taking a day off between practice sessions.

Our goal is, in part, to learn new habits and then reflect on how well they fit, on where they might help us most and where they might get in the way. We'll have better success learning new habits in the compressed term than we would with breaks. And, as much as I want students to work daily during a fifteen-week semester to build habits, it usually just doesn't happen. Even when the students buy in and intend to work that way, life's other demands get in the way. Failing with good intentions is still failing, and sometimes feels worse than failing without them.

So we begin. Tomorrow we start working on our first practice, a new way of working with skills to be learned through repetition every day the rest of the semester. Wish us luck.


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

May 09, 2014 4:11 PM

Transition

Spring semester ends today. May term begins Monday. I haven't taught during the summer since 2010, when I offered a course on agile software development. I'm reprising that course this month, with nine hardy souls signed on for the mission. That means no break for now, just a new start. I like those.

I'm sure I could blog for hours on the thoughts running through my head for the course. They go beyond the readings we did last time and the project we built, though all that is in the mix, too.

For now, though, three passages that made the highlights of my recent reading. All fit nicely with the theme of college days and transition.

~~~~

First, this reminder from John Graham, a "self-made merchant" circa 1900, in a letter to his son at college.

Adam invented all the different ways in which a young man can make a fool of himself, and the college yell at the end of them is just a frill that doesn't change essentials.

College is a place all its own, but it's just a place. In many ways, it's just the place where young people spend a few years while they are young.

~~~~

Next, a writer tells a story of studying with Annie Dillard in college. During their last session together, she told the class:

If I've done my job, you won't be happy with anything you write for the next 10 years. It's not because you won't be writing well, but because I've raised your standards for yourself.

Whatever we "content" teach our students, raising their standards and goals is sometimes the most important thing we do. "Don't compare yourselves to each other", she says. Compare yourselves to the best writers. "Shoot there." This advice works just as well for our students, whether they are becoming software developers or computer scientists. (Most of our students end up being a little bit of both.)

It's better to aim at the standard set by Ward Cunningham or Alan Kay than at the best we can imagine ourselves doing right now.

~~~~

Now that I think about it, this last one has nothing to do with college or transitions. But it made me laugh, and after a long academic year, with no break imminent, a good laugh is worth something.

What do you call a rigorous demonstration that a statement is true?
  1. If "proof", then you're a mathematician.
  2. If "experiment", then you're a physicist.
  3. If you have no word for this concept, then you're an economist.

This is the first of several items in The Mathematical Dialect Quiz at Math with Bad Drawings. It adds a couple of new twists to the tongue-in-cheek differences among mathematicians, computer scientists, and engineers. With bad drawings.

Back to work.


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

May 07, 2014 3:39 PM

Thinking in Types, and Good Design

Several people have recommended Pat Brisbin's Thinking in Types for programmers with experience in dynamically-typed languages who are looking to grok Haskell-style typing. He wrote it after helping one of his colleagues of mine was get unstuck with a program that "seemed conceptually simple but resulted in a type error" in Haskell when implemented in a way similar to a solution in a language such as Python or Ruby.

This topic is of current interest to me at a somewhat higher level. Few of our undergrads have a chance to program in Haskell as a part of their coursework, though a good number of them learn Scala while working at a local financial tech company. However, about two-thirds of undergrads now start with a one or two semesters of Python, and types are something of a mystery to them. This affects their learning of Java and colors how they think about types if they take my course on programming languages.

So I read this paper. I have two comments.

First, let me say that I agree with my friends and colleagues who are recommending this paper. It is a clear, concise, and well-written description of how to use Haskell's types to think about a problem. It uses examples that are concrete enough that even our undergrads could implement with a little help. I may use this as a reading in my languages course next spring.

Second, I think think this paper does more than simply teach people about types in a Haskell-like language. It also gives a great example of how thinking about types can help programmers create better designs for their programs, even if they are working in an object-oriented language! Further, it hits right at the heart of the problem we face these days, with students who are used to working in scripting languages that provide high-level but very generic data structures.

The problem that Brisbin addresses happens after he helps his buddy create type classes and two instance classes, and they reach this code:

    renderAll [ball, playerOne, playerTwo]

renderAll takes a list of values that are Render-able. Unfortunately, in this case, the arguments come from two different classes... and Haskell does not allow heterogeneous lists. We could try to work around this feature of Haskell and "make it fit", but as Brisbin points out, doing so would cause you to lose the advantages of using Haskell in the first place. The compiler wouldn't be able to find errors in the code.

The Haskell way to solve the problem is to replace the generic list of stuff we pass to renderAll with a new type. With a new Game type that composes a ball with two players, we are able to achieve several advantages at once:

  • create a polymorphic render method for Game that passes muster with the type checker
  • allow the type checker to ensure that this element of our program is correct
  • make the program easier to extend in a type-safe way
  • our program is correct
  • and, perhaps most importantly, express the intent of the program more clearly

It's this last win that jumped off the page for me. Creating a Game class would give us a better object-oriented design in his colleague's native language, too!

Students who become accustomed to programming in languages like Python and Ruby often become accustomed to using untyped lists, arrays, hashes, and tuples as their go-to collections. They are oh, so, handy, often the quickest route to a program that works on the small examples at hand. But those very handy data structures promote sloppy design, or at least enable it; they make it easy not to see very basic objects living in the code.

Who needs a Game class when a Python list or Ruby array works out of the box? I'll tell you: you do, as soon as you try to almost anything else in your program. Otherwise, you begin working around the generality of the list or array, writing code to handle special cases really aren't special cases at all. They are simply unbundled objects running wild in the program.

Good design is good design. Most of the features of a good design transcend any particular programming style or language.

So: This paper is a great read! You can use it to learn better how to think like a Haskell programmer. And you can use it to learn even if thinking like a Haskell programmer is not your goal. I'm going to use it, or something like it, to help my students become better OO programmers.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Patterns, Software Development

April 23, 2014 3:29 PM

Simple Tests

As Corey Haines tells us, it really can be this simple:

def assert_equal(expected, actual, message)
  if expected != actual
    raise "Expected #{expected}, got #{actual}\n#{message}"
  end
end

Don't let the overhead of learning or using a test harness prevent you from starting. Write a test, then write some code. Or, if you prefer: Write some code, then write a test.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

April 21, 2014 2:45 PM

The Special Case Object Pattern in "Confident Ruby"

I haven't had a chance to pick up a copy of Avdi Grimm's new book, Confident Ruby, yet. I did buzz by the book's Pragmatic Programmers page, where I was able to pick up a sample chapter or two for elliptical reading.

The chapter "Represent special cases as objects" was my first look. This chapter and the "Represent do-nothing cases as null objects" chapter that follows deal with situations in which our program is missing a kind of object. The result is code that has too many responsibilities because there is no object charged with handling them.

The chapter on do-nothing cases is @avdi's re-telling of the Null Object pattern. Bobby Woolf workshopped his seminal write-up of this pattern at PLoP 1996 (the first patterns conference I attended) and later published an improved version in the fourth Pattern Languages of Program Design book. I had the great pleasure to correspond with Bobby as he wrote his original paper and to share a few ideas about the pattern.

@avdi's special cases chapter is a great addition to the literature. It shows several different ways in which our code can call out for a special case object in place of a null reference. It then shows how creating a new kind of object can make our code better in each case, giving concrete examples written in Ruby, in the context of processing input to a web app.

I was discussing the pattern and the chapter with a student, who asked a question about this example:

    if current_user
      render_logout_button
    else
      render_login_button
    end

This is the only example in which the if check is not eliminated after introducing the special case object, an instance of the new class, GuestUser. Instead, @avdi adds an authenticated? to the User and GuestUser classes, has them return true and false respectively, and then changes the original expression to:

    if current_user.authenticated?
      render_logout_button
    else
      render_login_button
    end

As the chapter tells us, using the authenticated? predicate makes the conditional statement express the programmer's intent more clearly. But it also says that "we can't get rid of the conditional". My student asked, "Why not?"

Of course we can. The question is whether we want to. (I have a hard time using words like "cannot", "never", and "always", because I can usually imagine an exception to the absolute...)

In this case, there is a lingering smell in the code that uses the special case object: authenticated? is a surrogate for type check. Indeed, it behaves just like a query to find the object's class so that we can tailor our behavior to receiver's type. That's just the sort of thing we don't have to do in an OO program.

The standard remedy for this code smell is to push the behavior into the classes and send the object, whatever its type, a message. Rather ask a user if it is authenticated so that we can render the correct button, we might ask it to render the correct button itself:

    current_user.render_button

...

class User def render_button render_logout_button end end

class GuestUser def render_button render_login_button end end

Unfortunately, it's not quite this simple. The render_logXXX_button methods don't live in the user classes, so the render_button methods need to send those messages to some other object. If the user object already knows to whom to send it, great. If not, then the send of the render_button message will need to send itself as an argument along with the message, so that the receiver can send the appropriate message back.

Either of these approaches requires us to let some knowledge from the original context leak into our User and GuestUser classes, and that creates a new form of coupling. Ideally, there will be a way to mitigate this coupling in the form of some other shared association. Ruby web developers know the answer to this better than I.

In any case, this may be what @avdi means when he says that we can't get rid of the if check. Doing so may create more downside than upside.

This turned into a great opportunity to discuss design with my student. Design is about trade-offs. Things never seem quite as simple in the trenches as they do when we learn the rules and heuristics of design. There is no perfect solution. Our goal as programmers should be to develop the ability to make informed decisions in these situations, taking into account the context in which we are working.

Patterns document design solutions and so must be used with care. One of the thing I love about the pattern form is that it encourages the writer to make as explicit as possible the context in which the solution applies and the forces that make its use more or less applicable. This helps the reader to face the possible trade-offs with his or her eyes wide open.

So, one minor improvement @avdi might make in this chapter is to elaborate on the reason underlying the assertion that we can't eliminate this particular if check. Otherwise, students of OOP are likely to ask the same question my student asked.

Of course, the answer may be obvious to Ruby web developers. In the end, working with patterns is like all other design: the more experience we have, the better.

This is a relatively minor issue, though. From what I've seen, "Confident Ruby" will be a valuable addition to most Ruby programmers' bookshelves.


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

April 17, 2014 3:30 PM

The "Subclass as Client" Pattern

A few weeks ago, Reginald Braithwaite wrote a short piece discouraging us from creating class hierarchies. His article uses Javascript examples, but I think he intends his advice to apply everywhere:

So if someone asks you to explain how to write a class hierarchy? Go ahead and tell them: "Don't do that!"

If you have done much object-oriented programming in a class-based language, you will recognize his concern with class hierarchies: A change to the implementation of a class high up in the hierarchy could break every class beneath it. This is often called the "fragile base class" problem. Fragile code can't be changed without a lot of pain, fixing all the code broken by the change.

I'm going to violate the premise of Braithwaite's advice and suggest a way that you can make your base classes less fragile and thus make small class hierarchies more attractive. If you would like to follow his advice, feel free to tell me "Don't do that!" and stop reading now.

The technique I suggest follows directly from a practice that OO programmers use to create good objects, one that Braithwaite advocates in his article: encapsulating data tightly within an object.

JavaScript does not enforce private state, but it's easy to write well-encapsulated programs: simply avoid having one object directly manipulate another object's properties. Forty years after Smalltalk was invented, this is a well-understood principle.

The article then shows a standard example of a bank account object written in this style, in which client code uses the object without depending on its implementation. So far, so good.

What about classes?

It turns out, the relationship between classes in a hierarchy is not encapsulated. This is because classes do not relate to each other through a well-defined interface of methods while "hiding" their internal state from each other.

Braithwaite then shows an example of a subclass method that illustrates the problem:

    ChequingAccount.prototype.process = function (cheque) {
      this._currentBalance = this._currentBalance - cheque.amount();
      return this;
    }

The ChequingAccount directly accesses its _currentBalance member, which it inherits from the Account prototype. If we now change the internal implementation of Account so that it does not provide a _currentBalance member, we will break ChequingAccount.

The problem, we are told, is that objects are encapsulated, but classes are not.

... this dependency is not limited in scope to a carefully curated interface of methods and behaviour. We have no encapsulation.

However, as the article pointed out earlier, JavaScript does not enforce private state for objects! Even so, it's easy to write well-encapsulated programs -- by not letting one object directly manipulate another object's properties. This is a design pattern that makes it possible to write OO programs even when the language does not enforce encapsulation.

The problem isn't that objects are encapsulated and classes are not. It's that we tend treat superclasses differently than we treat other classes.

When we write code for two independent objects, we think of their classes as black boxes, sealed off from external inspection. The data and methods defined in the one class belong to it and its objects. Objects of one class must interact with objects of another via a carefully curated interface of methods and behavior.

But when we write code for a subclass, we tend to think of the data and methods defined in the superclass as somehow "belonging to" instances of the subclass. We take the notion of inheritance too literally.

My suggestion is that you treat your classes like you treat objects: Don't let one class look into another class and access its state directly. Adopt this practice even when the other class is a superclass, and the state is an inherited member.

Many OO programs have this pattern. I usually call it the "Subclass as Client" pattern. Instances of a subclass act as clients of their superclass, treating it -- as much as possible -- as an independent object providing a set of well-defined behaviors.

When code follows this pattern, it takes Braithwaite's advice for designing objects up a level and follows it more faithfully. Even instance variables inherited from the superclass are encapsulated, accessible only through the behaviors of the superclass.

I don't program in Javascript, but I've written a lot of Java over the years, and I think the lessons are compatible. Here's my story.

~~~~~

When I teach OOP, one of the first things my students learn about creating objects is this:

All instance variables are private.

Like Javascript, Java doesn't require this. We can tell the compiler to enforce it, though, through use of the private modifier. Now, only methods defined in the same class can access the variable.

For the most part, students are fine with this idea -- until we learn about subclasses. If one class extends another, it cannot access the inherited data members. The natural thing to do is what they see in too many Java examples in their texts and on the web: change private variables in the superclass to protected. Now, all is right with the world again.

Except that they have stepped directly into the path of the fragile base class problem. Almost any change to the superclass risks breaking all of its subclasses. Even in a sophomore OO course, we quickly encounter the problem of fragile base classes in our programs. But other choice do we have?

Make each class a server to its subclasses. Keep the instance variables private, and (in Braithwaite's words) carefully curate an interface of methods for subclasses to use. The class may be willing to expose more of its identity to its subclasses than to arbitrary objects, so define protected methods that are accessible only to its subclasses.

This is an intentional extension of the class's interface for explicit interaction with subclasses. (Yes, I know that protected members in Java are accessible to every class in the package. Grrr.)

This is the same discipline we follow when we write well-behaved objects in any language: encapsulate data and define an interface for interaction. When applied to the class-subclass relationship, it helps us to avoid the dangers of fragile base classes.

Forty years after Smalltalk was invented, this principle should be better understood by more programmers. In Smalltalk, variables are encapsulated within their classes, which forces subclasses to access them through methods defined in the superclass. This language feature encourages the writer of the class to think explicitly about how instances of a subclass will interact with the class. (Unfortunately, those methods are public to the world, so programmers have to enforce their scope by convention.)

Of course, a lazy programmer can throw away this advantage. When I first learned OO in Smalltalk, I quickly figured out that I could simply define accessors with the same names as the instance variables. Hurray! My elation did not last long, though. Like my Java students, I quickly found myself with a maze of class-subclass entanglements that made programming unbearable. I had re-invented the Fragile Base Class problem.

Fortunately, I had the Smalltalk class library to study, as well as programs written by better programmers than I. Those programs taught me the Subclass as Client pattern, I learned that it was possible to use subclasses well, when classes were designed carefully. This is just one of the many ways that Smalltalk taught me OOP.

~~~~~

Yes, you should prefer composition to inheritance, and, yes, you should strive to keep your class hierarchies as small and shallow as possible. But if you apply basic principles of object design to your superclasses, you don't need to live in absolute fear of fragile base classes. You can "do that" if you are willing to carefully curate an interface of methods that define the behavior of a class as a superclass.

This advice works well only for the class hierarchies you build for yourself. If you need to work with a class from an external package you don't control, then you can't be control the quality of those class's interfaces. Think carefully before you subclass an external class and depend on its implementation.

One technique I find helpful in this regard is to build a wrapper class around the external class, carefully define an interface for subclasses, and then extend the wrapper class. This at least isolates the risk of changes in the library class to a single class in my program.

Of course, if you are programming in Javascript, you might want to look to the Self community for more suitable OO advice than to Smalltalk!


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

March 31, 2014 3:21 PM

Programming, Defined and Re-imagined

By Chris Granger of Light Table fame:

Programming is our way of encoding thought such that the computer can help us with it.

Read the whole piece, which recounts Granger's reflection after the Light Table project left him unsatisfied and he sought answers. He concludes that we need to re-center our idea of what programming is and how we can make it accessible to more people. Our current idea of programming doesn't scale because, well,

It turns out masochism is a hard sell.

Every teacher knows this. You can sell masochism to a few proud souls, but not to anyone else.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

March 29, 2014 10:06 AM

Sooner

That is the advice I find myself giving to students again and again this semester: Sooner.

Review the material we cover in class sooner.

Ask questions sooner.

Think about the homework problems sooner.

Clarify the requirements sooner.

Write code sooner.

Test your code sooner.

Submit a working version of your homework sooner. You can submit a more complete version later.

A lot of this advice boils down to the more general Get feedback sooner. In many ways, it is a dual of the advice, Take small steps. If you take small steps, you can ask, clarify, write, and test sooner. One of the most reliable ways to do those things sooner is to take small steps.

If you are struggling to get things done, give sooner a try. Rather than fail in a familiar way, you might succeed in an unfamiliar way. When you do, you probably won't want to go back to the old way again.


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

March 18, 2014 2:30 PM

Deploy So That You Can Learn The Rest

In this interview prior to Monday's debut of FiveThirtyEight, Joe Coscarelli asked Nate Silver if the venture was ready to launch. Silver said that they they were probably 75-80% ready and that it was time to go live.

You're going to make some mistakes once you launch that you can't really deal with until you actually have a real product.

If they waited another month, they'd probably feel like they were ... 75-80% ready. There are some things you can't learn "unless your neck is on the line".

It ought not be surprising that Silver feels this way. His calling card is using data to make better decisions. Before you can have big data, or good data, you have to have data. It is usually better to start collecting it now than to start collecting it later.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

March 14, 2014 3:47 PM

We're in a Dr. Seuss Book

Sass, Flexbox, Git, Grunt? Frank Chimero whispers:

(Look at that list, programmers. You need to get better at naming things. No wonder why people are skittish about development. It's like we're in a Dr. Seuss book.)

For new names, it's time to hunt.
I will not Git!
I will not Grunt!

Nevermore shall we let these pass.
No more Flexbox!
No more Sass!


Posted by Eugene Wallingford | Permalink | Categories: Software Development

March 11, 2014 4:52 PM

Change The Battle From Arguments To Tests

In his recent article on the future of the news business, Marc Andreessen has a great passage in his section on ways for the journalism industry to move forward:

Experimentation: You may not have all the right answers up front, but running many experiments changes the battle for the right way forward from arguments to tests. You get data, which leads to correctness and ultimately finding the right answers.

I love that clause: "running many experiments changes the battle for the right way forward from arguments to tests".

While programming, it's easy to get caught up in what we know about the code we have just written and assume that this somehow empowers us to declare sweeping truths about what to do next.

When students are first learning to program, they often fall into this trap -- despite the fact that they don't know much at all. From other courses, though, they are used to thinking for a bit, drawing some conclusions, and then expressing strongly-held opinions. Why not do it with their code, too?

No matter who we are, whenever we do this, sometimes we are right, and sometimes, we are wrong. Why leave it to chance? Run a simple little experiment. Write a snippet of code that implements our idea, and run it. See what happens.

Programs let us test our ideas, even the ideas we have about the program we are writing. Why settle for abstract assertions when we can do better? In the end, even well-reasoned assertions are so much hot air. I learned this from Ward Cunningham: It's all talk until the tests run.


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

March 08, 2014 10:18 AM

Sometimes a Fantasy

This week I saw a link to The Turing School of Software & Design, "a seven-month, full-time program for people who want to become professional developers". It reminded me of Neumont University, a ten-year-old school that offers a B.S. degree program in Computer science that students can complete in two and a half years.

While riding the bike, I occasionally fantasize about doing something like this. With the economics of universities changing so quickly [ 1 | 2 ], there is an opportunity for a new kind of higher education. And there's something appealing about being able to work closely with a cadre of motivated students on the full spectrum of computer science and software development.

This could be an accelerated form of traditional CS instruction, without the distractions of other things, or it could be something different. Traditional university courses are pretty confining. "This course is about algorithms. That one is about programming languages." It would be fun to run a studio in which students serve as apprentices making real stuff, all of us learning as we go along.

A few years ago, one of our ChiliPLoP hot topic groups conducted a greenfield thought experiment to design an undergrad CS program outside of the constraints of any existing university structure. Student advancement was based on demonstrating professional competencies, not completing packaged courses. It was such an appealing idea! Of course, there was a lot of hard work to be done working out the details.

My view of university is still romantic, though. I like the idea of students engaging the great ideas of humanity that lie outside their major. These days, I think it's conceivable to include the humanities and other disciplines in a new kind of CS education. In a recent blog entry, Hollis Robbins floats the idea of Home College for the first year of a liberal arts education. The premise is that there are "thousands of qualified, trained, energetic, and underemployed Ph.D.s [...] struggling to find stable teaching jobs". Hiring a well-rounded tutor could be a lot less expensive than a year at a private college, and more lucrative for the tutor than adjuncting.

Maybe a new educational venture could offer more than targeted professional development in computing or software. Include a couple of humanities profs, maybe some a social scientist, and it could offer a more complete undergraduate education -- one that is economical both in time and money.

But the core of my dream is going broad and deep in CS without the baggage of a university. Sometimes a fantasy is all you need. Other times...


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

March 07, 2014 2:24 PM

Take Small Steps

If a CS major learns only one habit of professional practice in four years, it should be:

Take small steps.

A corollary:

If things aren't working, take smaller steps.

I once heard Kent Beck say something similar, in the context of TDD and XP. When my colleague Mark Jacobson works with students who are struggling, he uses a similar mantra: Solve a simpler problem. As Dr. Nick notes, students and professionals alike should scale the step size according to their level of knowledge or their confidence about the problem.

When I tweeted these thoughts yesterday, two pieces of related advice came in:

  • Slow down. -- Big steps are usually a sign of trying to hurry. Beginners are especially prone to this.

  • Lemma: Keep moving. -- Small steps keep us moving more reliably. We can always fool ourselves into believing that the next big step is all we need...

Of course, I've always been a fan of baby steps and unusual connections to agile software development. They apply quite nicely to learners in many settings.


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

March 01, 2014 11:35 AM

A Few Old Passages

I was looking over a couple of files of old notes and found several quotes that I still like, usually from articles I enjoyed as well. They haven't found their way into a blog entry yet, but they deserve to see the light of day.

Evidence, Please!

From a short note on the tendency even among scientists to believe unsubstantiated claims, both in and out of the professional context:

It's hard work, but I suspect the real challenge will lie in persuading working programmers to say "evidence, please" more often.

More programmers and computer scientists are trying to collect and understand data these days, but I'm not sure we've made much headway in getting programmers to ask for evidence.

Sometimes, Code Before Math

From a discussion of The Expectation Maximization Algorithm:

The code is a lot simpler to understand than the math, I think.

I often understand the language of code more quickly than the language of math. Reading, or even writing, a program sometimes helps me understand a new idea better than reading the math. Theory is, however, great for helping me to pin down what I have learned more formally.

Grin, Wave, Nod

From Iteration Inside and Out, a review of the many ways we loop over stuff in programs:

Right now, the Rubyists are grinning, the Smalltalkers are furiously waving their hands in the air to get the teacher's attention, and the Lispers are just nodding smugly in the back row (all as usual).

As a Big Fan of all three languages, I am occasionally conflicted. Grin? Wave? Nod? Look like the court jester by doing all three simultaneously?


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

February 16, 2014 10:48 AM

Experience Happens When You Keep Showing Up

You know what they say about good design coming from experience, and experience coming from bad design? That phenomenon is true of most things non-trivial. Here's an example from men's college basketball.

The University of Florida has a veteran team. The University of Kentucky has a young team. Florida's players are very good, but not generally considered to be in the same class as Kentucky's highly-regarded players. Yesterday, the two teams played a close game on Kentucky's home floor.

Once they fell behind by five with less than two minutes remaining, Kentucky players panicked. Florida players didn't. Why not? "Well, we have a veteran group here that's panicked before -- that's been in this situation and not handled it well," [Patric] Young said.

How did Florida's players maintain their composure at the end of a tight game on the road against another good team? They had been in that same situation three times before, and failed. They didn't panic this time in large part because they had panicked before and learned from those experiences.

Kentucky's starters have played a total of 124 college games. Florida's four seniors have combined to play 491. That's a lot of experience -- a lot of opportunities to panic, to guess wrong, to underestimate a situation, or otherwise to come up short. And a lot of opportunities to learn.

The young players at Kentucky hurt today. As the author of the linked game report notes, Florida's players have hurt like that before, for coming up short in much the same way, "and they used that pain to get better".

It turns out that composure comes from experience, and experience comes from lack of composure.

As a teacher, I try to convince students not to shy away from the error messages their compiler gives them, or from the convoluted code they eventually sneak past it. Those are the experiences they'll eventually look back to when they are capable, confident programmers. They just need the opportunity to learn.


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

February 14, 2014 3:07 PM

Do Things That Help You Become Less Wrong

My students and I debriefed a programming assignment in class yesterday. In the middle of class, I said, "Now for a big question: How do you know your code is correct?

There were a lot of knowing smiles and a lot of nervous laughter. Most of them don't.

Sure, they ran a few test cases, but after making additions and changes to the code, some were just happy that it still ran. The output looked reasonable, so it must be done. I suggested that they might want to think more about testing.

This morning I read a great quote from Nathan Marz that I will share with my students:

Feedback is everything. Most of the time you're wrong, and feedback is the only way to realize your mistakes and help you become less wrong. This applies to everything.

Most of the time you're wrong. Do things that help you become less wrong. Getting feedback, early and often, is one of the best ways to do this.

A comment by a student earlier in the period foreshadowed our discussion of testing, which made me feel even better. In response to the retrospective question, "What design or programming choices went well for you?", he answered unit tests.

That set me up quite nicely to segue from manual testing into automated testing. If you aren't testing your code early and often, then manual testing is a huge improvement. But you can do even better by pushing those test cases into a form that can be executed quickly and easily, with the code doing the tedious work of verifying the output.

My students are writing code in many different languages, so I showed them testing frameworks in Ruby, Java, and Python. The code looks simple, even with the boilerplate imposed by the frameworks.

The big challenges in getting students to write unit tests are the same as for getting professionals to write them: lack of time, and misplaced confidence. I hope that a few of my students will see that the real time sink is debugging bad code and that a fear of changing code is a lack of confidence. The best way to be confident is to have evidence.

The student who extolled unit tests works in Racket and so has test cases in RackUnit. He set me up nicely for a future discussion, too, when he admitted out loud that he wrote his tests first. This time, it was I who smiled knowingly.


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

January 31, 2014 3:13 PM

"What Should It Be?"

When asked to design and implement a program, beginning programmers often aren't sure what data type or data structure to use for a particular value. Should they use an array or a list? Or they've decided to use a record but can't decide exactly what fields to include, or names to give them.

"What should it be?", they ask.

I often have a particular implementation in mind, based on what we've been studying or on my own experience as a programmer, but I prefer not to tell them what to do. This is a great opportunity for them to learn to think about design.

Instead, I ask questions. "What have you considered?" "Do you think one or the other is better?" "Why?"

We discuss how so often there is no "right" answer. There are merely trade-offs. They have to choose. This is a design decision.

But, in making this decision, there's another opportunity to learn something about design. They don't have to commit now and forever to an implementation before proceeding with the rest of their program. Because the rest of the program shouldn't know about their decision anyway!

They should make an object that encapsulates the choice. They are then able to start building the rest of the program without fear that it depends on the details of their design choice. The rest of the program will interact with the object in terms of what the object means in the program, not in terms of how it is implemented. Later, if they change their minds, they will be able to change the implementation details without disturbing the rest of the code.

Yes this is basic stuff, but beginners often struggle with basic stuff. They've learned about ADTs or OOP, and they can talk abstractly about abstraction. But when it comes time to write code, indecision descends upon them. They are afraid of messing up.

If I can help allay their fears of proceeding, then I've contributed something to their work that day. I even suggest that writing the rest of the program might even help them figure out which alternative is better. I like to listen to my code, even if that idea seems strange or absurd to them. Some day soon, it may not.

In any case, they have the beginnings of a program, and perhaps a better idea of what design is all about.


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

January 24, 2014 2:18 PM

Could I be a programmer?

... with apologies to Annie Dillard.

A well-known programmer got collared by a university student who asked, "Do you think I could be a programmer?"

"Well," the programmer said, "I don't know... Do you like function calls?"

The programmer could see the student's amazement. Function calls? Do I like function calls? I am twenty years old and do I like function calls?

If the student had liked function calls, of course, he could begin, like a joyful painter I knew. I asked him how he came to be a painter. He said, "I liked the smell of paint."


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

January 08, 2014 3:06 PM

"I'm Not a Programmer"

In The Exceptional Beauty of Doom 3's Source Code, Shawn McGrath first says this:

I've never really cared about source code before. I don't really consider myself a 'programmer'.

Then he says this:

Dyad has 193k lines of code, all C++.

193,000 lines of C++? Um, dude, you're a programmer.

Even so, the point is worth thinking about. For most people, programming is a means to an end: a way to create something. Many CS students start with a dream program in mind and only later, like McGrath, come to appreciate code for its own sake. Some of our graduates never really get there, and appreciate programming mostly for what they can do with it.

If the message we send from academic CS is "come to us only if you already care about code for its own sake", then we may want to fix our message.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

December 20, 2013 3:01 PM

Sometimes, Good Design is Simple

In an article on the Moonpig billing system, Mark Dominus writes:

Sometimes I see other people [screw] up a project over and over, and I say "I could do that better", and then I get a chance to try, and I discover it was a lot harder than I thought, I realize that those people who tried before are not as stupid as as I believed.

That did not happen this time.

Sometimes, good design is pretty simple. Separate interface from implementation. Create simple abstraction layers to separate different levels of functionality. Encapsulate data and behavior in objects that circumscribe potential change.

I liked a few of the specific tactics described, too:

Don't use raw primitives from the language, even standard classes. "Instead of using raw DateTime [a standard Perl class], we wrapped it in a derived class called Moonpig::DateTime."

Define convenience functions that hide underlying data implementations. Moonpig does this in several places, most notably money and time.

Use mutable data sparingly, and never for values. One way Moonpig does this is to implement "values with history", an idea I first learned from Ralph Johnson in Smalltalk. Each new value for an entity is pushed onto an array. When a piece of code asks for the current value, it receives the top of the array.

Object-oriented programming is centered around objects. That means encapsulated behavior. Other concepts, such as classes and inheritance, are add-ons. Dominus is especially hard on inheritance, based on past experience. I agree that it must be used carefully and sparingly. I like how Moonpig uses roles to eliminate the need for classes entirely in the application.

This was a fun read.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

December 17, 2013 3:32 PM

Always Have At Least Two Alternatives

Paraphrasing Kent Beck:

Whenever I write a new piece of code, I like to have at least two alternatives in mind. That way, I know I am not doing the worst thing possible.

I heard Kent say something like this at OOPSLA in the late 1990s. This is advice I give often to students and colleagues, but I've never had a URL that I could point them to.

It's tempting for programmers to start implementing the first good idea that comes to mind. It's especially tempting for novices, who sometimes seem surprised that they have even one good idea. Where would a second one come from?

More experienced students and programmers sometimes trust their skill and experience a little too easily. That first idea seems so good, and I'm a good programmer... Famous last words. Reality eventually catches up with us and helps us become more humble.

Some students are afraid: afraid they won't get done if they waste time considering alternatives, or afraid that they will choose wrong anyway. Such students need more confidence, the kind born out of small successes.

I think the most likely explanation for why beginners don't already seek alternatives is quite simple. They have not developed the design habit. Kent's advice can be a good start.

One pithy statement is often enough of a reminder for more experienced programmers. By itself, though, it probably isn't enough for beginners. But it can be an important first step for students -- and others -- who are in the habit of doing the first thing that pops into their heads.

Do note that this advice is consistent with XP's counsel to do the simplest thing that could possibly work. "Simplest" is a superlative. Grammatically, that suggests having at least three options from which to choose!


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

December 10, 2013 3:33 PM

Your Programming Language is Your Raw Material, Too

Recently someone I know retweeted this familiar sentiment:

If carpenters were hired like programmers:
"Must have at least 5 years experience with the Dewalt 18V 165mm Circular Saw"

This meme travels around the world in various forms all the time, and every so often it shows up in one of my inboxes. And every time I think, "There is more to the story."

In one sense, the meme reflects a real problem in the software world. Job ads often use lists of programming languages and technologies as requirements, when what the company presumably really wants is a competent developer. I may not know the particular technologies on your list, or be expert in them, but if I am an experienced developer I will be able to learn them and become an expert.

Understanding and skill run deeper than a surface list of tools.

But. A programming language is not just a tool. It is a building material, too.

Suppose that a carpenter uses a Dewalt 18V 165mm circular saw to add a room to your house. When he finishes the project and leaves your employ, you won't have any trace of the Dewalt in his work product. You will have a new room.

He might have used another brand of circular saw. He may not have used a power tool at all, preferring the fine craftsmanship of a handsaw. Maybe he used no saw of any kind. (What a magician!) You will still have the same new room regardless, and your life will proceed in the very same way.

Now suppose that a programmer uses the Java programming language to add a software module to your accounting system. When she finishes the project and leaves your employ, you will have the results of running her code, for sure. But you will have a trace of Java in her work product. You will have a new Java program.

If you intend to use the program again, to generate a new report from new input data, you will need an instance of the JVM to run it. If want to modify the program to work differently, then you will also need a Java compiler to create the byte codes that run in the JVM. If you want to extend the program to do more, then you again will need a Java compiler and interpreter.

Programs are themselves tools, and we use programming languages to build them. So, while the language itself is surely a tool at one level, at another level it is the raw material out of which we create other things.

To use a particular language is to introduce a slew of other dependencies to the overall process: compilers, interpreters, libraries, and sometimes even machine architectures. In the general case, to use a particular language is to commit at least some part of the company's future attention to both the language and its attendant tooling.

So, while I am sympathetic to sentiment behind our recurring meme, I think it's important to remember that a programming language is more than just a particular brand of power tool. It is the stuff programs are made of.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

December 08, 2013 11:48 AM

Change Happens When People Talk to People

I finally got around to reading Atul Gawande's Slow Ideas this morning. It's a New Yorker piece from last summer about how some good ideas seem to resist widespread adoption, despite ample evidence in their favor, and ways that one might help accelerate their spread.

As I read, I couldn't help but think of parallels to teaching students to write programs and helping professionals develop software more reliably. We know that development practices such as version control, short iterations, and pervasive testing lead to better software and more reliable process. Yet they are hard habits for many programmers to develop, especially when they have conflicting habits in place.

Other development practices seem counterintuitive. "Pair programming can't work, right?" In these cases, we have to help people overcome both habits of practice and habits of thought. That's a tall order.

Gawande's article is about medical practice, from surgeons to home practitioners, but his conclusions apply to software development as well. For instance: People have an easier time changing habits when the benefit is personal, immediate, and visceral. When the benefit is not so obvious, a whole new way of thinking is needed. That requires time and education.

The key message to teach surgeons, it turned out, was not how to stop germs but how to think like a laboratory scientist.

This is certainly true for software developers. (If you replace "germs" with "bugs", it's an even better fit!) Much of the time, developers have to think about evidence the ways scientists do.

This lesson is true not just for surgeons and software developers. It is true for most people, in most ways of life. Sometimes, we all have to be able to think and act like a scientist. I can think of no better argument for treating science as important for all students, just as we do reading and writing.

Other lessons from Gawande's article are more down-to-earth:

Many of the changes took practice for her, she said. She had to learn, for instance, how to have all the critical supplies -- blood-pressure cuff, thermometer, soap, clean gloves, baby respiratory mask, medications -- lined up and ready for when she needed them; how to fit the use of them into her routine; how to convince mothers and their relatives that the best thing for a child was to be bundled against the mother's skin. ...

So many good ideas in one paragraph! Many software development teams could improve by putting them in action:

  • Construct a work environment with essential tools ready at hand.
  • Adjust routine to include new tools.
  • Help collaborators see and understand the benefit of new habits.
  • Practice, practice, practice.

Finally, the human touch is essential. People who understand must help others to see and understand. But when we order, judge, or hector people, they tend to close down the paths of communication, precisely when we need them to be most open. Gawande's colleagues have been most successful when they built personal relationships:

"It wasn't like talking to someone who was trying to find mistakes," she said. "It was like talking to a friend."

Good teachers know this. Some have to learn it the hard way, in the trenches with their students. But then, that is how Gawande's colleagues learned it, too.

"Slow Hands" is good news for teachers all around. It teaches ways to do our job better. But also, in many ways, it tells us that teaching will continue to matter in an age dominated by technological success:

People talking to people is still how the world's standards change.


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

December 04, 2013 3:14 PM

Agile Moments, "Why We Test" Edition

Case 1: Big Programs.

This blog entry tells the sad story of a computational biologist who had to retract six published articles. Why? Their conclusions depended on the output of a computer program, and that program contained a critical error. The writer of the entry, who is not the researcher in question, concludes:

What this should flag is the necessity to aggressively test all the software that you write.

Actually, you should have tests for any program you use to draw important conclusions, whether you wrote it or not. The same blog entry mentions that a grad student in the author's previous lab had found several bugs a molecular dynamics program used by many computational biologists. How many published results were affected before they were found?

Case 2: Small Scripts.

Titus Brown reports finding bugs every time he reused one of his Python scripts. Yet:

Did I start doing any kind of automated testing of my scripts? Hell no! Anyone who wants to write automated tests for all their little scriptlets is, frankly, insane. But this was one of the two catalysts that made me personally own up to the idea that most of my code was probably somewhat wrong.

Most of my code has bugs but, hey, why write tests?

Didn't a famous scientist define insanity as doing the same thing over and over but expecting different results?

I consider myself insane, too, but mostly because I don't write tests often enough for my small scripts. We say to ourselves that we'll never reuse them, so we don't need tests. But we don't throw them away, and then we do reuse them, perhaps with a tweak here or there.

We all face time constraints. When we run a script the first time, we may well pay enough attention to the output that we are confident it is correct. But perhaps we can all agree that the second time we use a script, we should write tests for it if we don't already have them.

There are only three numbers in computing, 0, 1, and many. The second time we use a program is a sign from the universe that we need the added confidence provided by tests.

To be fair, Brown goes on to offer some good advice, such as writing tests for code after you find a bug in it. His article is an interesting read, as is almost everything he writes about computation and science.

Case 3: The Disappointing Trade-Off.

Then there's this classic from Jamie Zawinski, as quoted in Coders at Work:

I hope I don't sound like I'm saying, "Testing is for chumps." It's not. It's a matter of priorities. Are you trying to write good software or are you trying to be done by next week? You can't do both.

Sigh. If you you don't have good software by next week, maybe you aren't done yet.

I understand that the real world imposes constraints on us, and that sometimes worse is better. Good enough is good enough, and we rarely need a perfect program. I also understand that Zawinski was trying to be fair to the idea of testing, and that he was surely producing good enough code before releasing.

Even still, the pervasive attitude that we can either write good programs or get done on time, but not both, makes me sad. I hope that we can do better.

And I'm betting that the computational biologist referred to in Case 1 wishes he had had some tests to catch the simple error that undermined five years worth of research.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

December 03, 2013 3:17 PM

The Workaday Byproducts of Striving for Higher Goals

Why set audacious goals? In his piece about the Snowfall experiment, David Sleight says yes, and not simply for the immediate end:

The benefits go beyond the plainly obvious. You need good R&D for the same reason you need a good space program. It doesn't just get you to the Moon. It gives you things like memory foam, scratch-resistant lenses, and Dustbusters. It gets you the workaday byproducts of striving for higher goals.

I showed that last sentence a little Twitter love, because it's something people often forget to consider, both when they are working in the trenches and when they are selecting projects to work on. An ambitious project may have a higher risk of failure than something more mundane, but it also has a higher chance of producing unexpected value in the form of new tools and improved process.

This is also something that university curricula don't do well. We tend to design learning experiences that fit neatly into a fifteen-week semester, with predictable gains for our students. That sort of progress is important, of course, but it misses out on opportunities for students to produce their own workaday byproducts. And that's an important experience for students to have.

It also gives a bad example of what learning should feel like, and what it should do for us. Students generally learn what we teach them, or what we make easiest for them to learn. If we always set before them tasks of known, easily-understood dimensions, then they will have to learn after leaving us that the world doesn't usually work like that.

This is one of the reasons I am such a fan of project-based computer science education, as in the traditional compiler course. A compiler is an audacious enough goal for most students that they get to discover their own personal memory foam.


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

November 25, 2013 2:56 PM

The Moment When Design Happens

Even when we plan ahead a bit, the design of a program tends to evolve. Gary Bernhardt gives an example in his essay on abstraction:

If I feel the need to violate the abstraction, I need to reconsider how to modify the boundaries to match that need, rather than violating the boundaries by crossing them.

This is the moment when design happens...

This is a hard design lesson to give students, because it is likely to click with them only after living with the consequences of violating the abstraction. This requires working with the same large program over time, preferably one they are building along the way.

This is one of the reasons I so like our senior project courses. My students are building a compiler this term, which gives them a chance to experience a moment when design happens. Their abstract syntax trees and symbol tables are just the sort of abstractions that invite violation -- and reward a little re-design.


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

November 21, 2013 3:06 PM

Agile Thoughts, Healthcare.gov Edition

Clay Shirky explains the cultural attitudes that underlie Healthcare.gov's problems in his recent essay on the gulf between planning and reality. The danger of this gulf exists in any organization, whether business or government, but especially in large organizations. As the number of levels grows between the most powerful decision makers and the workers in the trenches, there is an increasing risk of developing "a culture that prefers deluding the boss over delivering bad news".

But this is also a story of the danger inherent in so-called Big Design Up Front, especially for a new kind of product. Shirky oversimplifies this as the waterfall method, but the basic idea is the same:

By putting the most serious planning at the beginning, with subsequent work derived from the plan, the waterfall method amounts to a pledge by all parties not to learn anything while doing the actual work.

You may learn something, of course; you just aren't allowed to let it change what you build, or how.

Instead, waterfall insists that the participants will understand best how things should work before accumulating any real-world experience, and that planners will always know more than workers.

If the planners believe this, or they allow the workers to think they believe this, then workers will naturally avoid telling their managers what they have learned. In the best case, they don't want to waste anyone's time if sharing the information will have no effect. In the worst case, they might fear the results of sharing what they have learned. No one likes to admit that they can't get the assigned task done, however unrealistic it is.

As Shirky notes, many people believe that a difficult launch of Healthcare.gov was unavoidable, because political and practical factors prevented developers from testing parts of the project as they went along and adjusting their actions in response. Shirky hits this one out of the park:

That observation illustrates the gulf between planning and reality in political circles. It is hard for policy people to imagine that Healthcare.gov could have had a phased rollout, even while it is having one.

You can learn from feedback earlier, or you can learn from feedback later. Pretending that you can avoid problems you already know exist never works.

One of the things I like about agile approaches to software development is they encourage us not to delude ourselves, or our clients. Or our bosses.


Posted by Eugene Wallingford | Permalink | Categories: General, Managing and Leading, Software Development

November 19, 2013 4:49 PM

First Model, Then Improve

Not long ago, I read Unhappy Truckers and Other Algorithmic Problems, an article by Tom Vanderbilt that looks at efforts to optimize delivery schedules at UPS and similar companies. At the heart of the challenge lies the traveling salesman problem. However, in practice, the challenge brings companies face-to-face with a bevy of human issues, from personal to social, psychological to economic. As a result, solving this TSP is more complex than what we see in the algorithms courses we take in our CS programs.

Yet, in the face of challenges both computational and human, the human planners working at these companies do a pretty good job. How? Over the course of time, researchers figured out that finding optimal routes shouldn't be their main goal:

"Our objective wasn't to get the best solution," says Ted Gifford, a longtime operations research specialist at Schneider. "Our objective was to try to simulate what the real world planners were really doing."

This is a lesson I learned the hard way, too, back in graduate school, when my advisor's lab was trying to build knowledge-based systems for real clients, in chemical engineering, aeronautics, business, and other domains. We were working with real people who were solving hard problems under serious constraints.

At the beginning I was a typically naive programmer, armed with fancy AI techniques and unbounded enthusiasm. I soon learned that, if you walk into a workplace and propose to solve all the peoples' problems with a program, things don't go as smoothly as the programmer might hope.

First of all, this impolitic approach generally creates immediate pushback. These are people, with personal investment in the way things work now. They tend to bristle when a 20-something grad student walks in the door promoting the wonder drug for all their ills. Some might even fear that you are right, and success for your program will mean negative consequences for them personally. We see this dynamic in Vanderbilt's article.

There's a deeper reason that things don't go so smoothly, though, and it's the real lesson of Vanderbilt's piece. Until you implement the existing solution to the problem, you don't really understand the problem yet.

These problems are complex, often with many more constraints than typical theoretical solutions have dealt with. The humans solving the problem often have many years of experience contributing to their approach. They have deep knowledge of the domain, but also repeated exposure to the exceptions and edge cases that sometimes confound theoretical solutions. They use heuristics that are hard to tease apart or articulate.

I learned that it's easy to solve a problem if you are solving the wrong one.

A better way to approach these challenges is: First, model the existing system, including the extant solution. Then, look for ways to improve on the solution.

This approach often gives everyone involved greater confidence that the programmers understand -- and so are solving -- the right problem. It also enables the team to make small, incremental changes to the system, with a correspondingly higher probability of success. Together, these two outcomes greatly increase the chance of human buy-in from the current workers. This makes it easier for the whole team to recognize the need for larger-scale changes to the process, and to support and contribute to an improved solution.

Vanderbilt tells a similarly pragmatic story. He writes:

When I suggest to Gifford that he's trying to understand the real world, mathematically, he concurs, but adds: "The word 'understand' is too strong--we are happy to get positive outcomes."

Positive outcomes are what the company wants. Fortunately for the academics who work on such problems in industry, achieving good outcomes is often an effective way to test theories, encounter their shortcomings, and work on improvements. That, too, is something I learned in grad school. It was a valuable lesson.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

November 04, 2013 2:41 PM

Those Silly Tests

I love this passage by Mark Dominus in Overlapping Intervals:

This was yet another time when I felt slightly foolish as I wrote the automated tests, assuming that the time and effort I spent on testing this trivial function would be time and effort thrown away on nothing -- and then they detected a real fault. Someday perhaps I'll stop feeling foolish writing tests for functions like this one; until then, many cases just like this one will help me remember that I must write the tests even though I feel foolish doing it.

Even excellent programmers feel silly writing tests sometimes. But they also benefit from writing them. Dominus was saved here by his test-writing habit, or by his sense of right and wrong.

Helping students develop that habit or that moral sense is a challenge. Even so, I rarely come across a situation where my students or I write or run too many tests. I regular encounter cases where we write or run too few.

Dominus's blog entry also a great passage on a larger lesson from that coding experience. In the end, his clever solution to a tricky problem results not from "just thinking" but from deeper thought: from "applying carefully-learned and practiced technique". That's an important form of thinking, too.


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

October 30, 2013 11:41 AM

Discipline Can Be Structural As Well As Personal

There is a great insight in an old post by Brian Marick, Discipline and Skill, which I re-read this week. The topic sentence asserts:

Discipline can be a personal virtue, but it must also be structural.

Extreme Programming illustrates this claim. It draws its greatest power from the structural discipline it creates for developers. Marick goes on:

For example, one of the reasons to program in pairs is that two people are less likely to skip a test than one is. Removing code ownership makes it more likely someone within glaring distance will see that you didn't leave code as clean as you should have. The business's absolute insistence on getting working -- really working -- software at frequent intervals makes the pain of sloppiness strike home next month instead of next year, stiffening the resolve to do the right thing today.

P consists of a lot of relatively simple actions, but simple actions can be hard to perform, especially consistently and especially in opposition to deeply ingrained habits. XP practices work together to create structural discipline that helps developers "do the right thing".

We see the use of social media playing a similar role these days. Consider diet. People who are trying to lose weight or exercise more have to do some pretty simple things. Unfortunately, those things are not easy to do consistently, and they are opposed by deep personal and cultural habits. In order to address this, digital tool providers like FitBit make it easy for users to sync their data to a social media account and share with others.

This is a form of social discipline, supported by tools and practices that give structure to the actions people want to take. Just like XP. Many behaviors in life work this way.

(Of course, I'm already on record as saying that XP is a self-help system. I have even fantasized about XP's relationship to self-help in the cinema.)


Posted by Eugene Wallingford | Permalink | Categories: General, Software Development

October 16, 2013 11:38 AM

Poetry as a Metaphor for Software

I was reading Roger Hui's Remembering Ken Iverson this morning on the elliptical, and it reminded me of this passage from A Conversation with Arthur Whitney. Whitney is a long-time APL guru and the creator of the A, K, and Q programming languages. The interviewer is Bryan Cantrill.

BC: Software has often been compared with civil engineering, but I'm really sick of people describing software as being like a bridge. What do you think the analog for software is?

AW: Poetry.

BC: Poetry captures the aesthetics, but not the precision.

AW: I don't know, maybe it does.

A poet's use of language is quite precise. It must balance forces in many dimensions, including sound, shape, denotation, and connotation. Whitney seems to understand this. Richard Gabriel must be proud.

Brevity is a value in the APL world. Whitney must have a similar preference for short language names. I don't know the source of his names A, K, and Q, but I like Hui's explanation of where J's name came from:

... on Sunday, August 27, 1989, at about four o'clock in the afternoon, [I] wrote the first line of code that became the implementation described in this document.

The name "J" was chosen a few minutes later, when it became necessary to save the interpreter source file for the first time.

Beautiful. No messing around with branding. Gotta save my file.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

October 10, 2013 5:17 AM

Software Design is a Bet on a Particular Future

This truth is expressed nicely by Reginald Braithwaite:

Software design is the act of making bets about the future. A well-designed program is a bet on what will change in the future, and what will not change. And a well-designed program communicates the nature of that bet by being relatively flexible about things that the designers think are most likely to change, and being relatively inflexible about the things the designers think are least likely to change.

That's what refactoring is all about, of course. Sometimes, a particular guess turns out to be wrong. We have the wrong factors, the wrong components, for adding a new feature. So we change the shape of the code -- we factor it into different components -- to reflect our new best understanding of the future. Then we move on.

Sometimes, though, there are forces that make more desirable a relatively monolithic piece of code (or, as Braithwaite points out, a system decomposed into relatively less flexible components). In these cases, we need to defactor, to use Braithwaite's term: we recombine some or all of the parts to create a new design.

Predicting the future is hard, even for experienced programmers. One of the goals of agile design is to not think too far ahead, because that means committing to a future too far removed from what we already know to be true about our program.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

October 07, 2013 12:07 PM

StrangeLoop: Exercises in Programming Style

[My notes on StrangeLoop 2013: Table of Contents]

Crista Lopes

I had been looking forward to Crista Lopes's StrangeLoop talk since May, so I made sure I was in the room well before the scheduled time. I even had a copy of the trigger book in my bag.

Crista opened with something that CS instructors have learned the hard way: Teaching programming style is difficult and takes a lot of time. As a result, it's often not done at all in our courses. But so many of our graduates go into software development for the careers, where they come into contact with many different styles. How can they understand them -- well, quickly, or at all?

To many people, style is merely the appearance of code on the screen or printed. But it's not. It's more, and something entirely different. Style is a constraint. Lopes used images of a few stylistic paintings to illustrate the idea. If an artist limits herself to pointillism or cubism, how can she express important ideas? How does the style limit the message, or enhance it?

But we know this is true of programming as well. The idea has been a theme in my teaching for many years. I occasionally write about the role of constraints in programming here, including Patterns as a Source of Freedom, a few programming challenges, and a polymorphism challenge that I've run as a workshop.

Lopes pointed to a more universal example, though: the canonical The Elements of Programming Style. Drawing on this book and other work in software, she said that programming style ...

  • is a way to express tasks
  • exists at all scales
  • recurs at multiple scales
  • is codified in programming language

For me, the last bullet ties back most directly to idea of style as constraint. A language makes some things easier to express than others. It can also make some things harder to express. There is a spectrum, of course. For example, some OO languages make it easy to create and use objects; others make it hard to do anything else! But the language is an enabler and enforcer of style. It is a proxy for style as a constraint on the programmer.

Back to the talk. Lopes asked, Why is it so important that we understand programming style? First, a style provides the reader with a frame of reference and a vocabulary. Knowing different styles makes us a more effective consumers of code. Second, one style can be more appropriate for a given problem or context than another style. So, knowing different styles makes us a more effective producers of code. (Lopes did not use the producer-consumer distinction in the talk, but it seems to me a nice way to crystallize her idea.)

the cover of Raymond Queneau's Exercises in Style

The, Lopes said, I came across Raymond Queneau's playful little book, "Exercises in Style". Queneau constrains himself in many interesting ways while telling essentially the same story. Hmm... We could apply the same idea to programming! Let's do it.

Lopes picked a well-known problem, the common word problem famously solved in a Programming Pearls column more than twenty-five years. This is a fitting choice, because Jon Bentley included in that column a critique of Knuth's program by Doug McIlroy, who considered both engineering concerns and program style in his critique.

The problem is straightforward: identify and print the k most common terms that occur in a given text document, in decreasing order. For the rest of the talk, Lopes presented several programs that solve the problem, each written in a different style, showing code and highlighting its shape and boundaries.

Python was her language of choice for the examples. She was looking for a language that many readers would be able to follow and understand, and Python has the feel of pseudo-code about it. (I tell my students that it is the Pascal of their time, though I may as well be speaking of hieroglyphics.) Of course, Python has strengths and weaknesses that affect its fit for some styles. This is an unavoidable complication for all communication...

Also, Lopes did not give formal names to the styles she demonstrated. Apparently, at previous versions of this talk, audience members had wanted to argue over the names more than the styles themselves! Vowing not to make that mistake again, she numbered her examples for this talk.

That's what programmers do when they don't have good names.

In lieu of names, she asked the crowd to live-tweet to her what they thought each style is or should be called. She eventually did give each style a fun, informal name. (CS textbooks might be more evocative if we used her names instead of the formal ones.)

I noted eight examples shown by Lopes in the talk, though there may have been more:

  • monolithic procedural code -- "brain dump"
  • a Unix-style pipeline -- "code golf"
  • procedural decomposition with a sequential main -- "cook book"
  • the same, only with functions and composition -- "Willy Wonka"
  • functional decomposition, with a continuation parameter -- "crochet"
  • modules containing multiple functions -- "the kingdom of nouns"
  • relational style -- (didn't catch this one)
  • functional with decomposition and reduction -- "multiplexer"

Lopes said that she hopes to produce solutions using a total of thirty or so styles. She asked the audience for help with one in particular: logic programming. She said that she is not a native speaker of that style, and Python does not come with a logic engine built-in to make writing a solution straightforward.

Someone from the audience suggested she consider yet another style: using a domain-specific language. That would be fun, though perhaps tough to roll from scratch in Python. By that time, my own brain was spinning away, thinking about writing a solution to the problem in Joy, using a concatenative style.

Sometimes, it's surprising just how many programming styles and meaningful variations people have created. The human mind is an amazing thing.

The talk was, I think, a fun one for the audience. Lopes is writing a book based on the idea. I had a chance to review an early draft, and now I'm looking forward to the finished product. I'm sure I'll learn something new from it.


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

October 04, 2013 3:12 PM

StrangeLoop: Rich Hickey on Channels and Program Design

[My notes on StrangeLoop 2013: Table of Contents]

Rich Hickey setting up for his talk

Rich Hickey spoke at one of the previous StrangeLoops I attended, but this was my first time to attend one of his talks in person. I took the shaky photo seen at the right as proof. I must say, he gives a good talk.

The title slide read "Clojure core.async Channels", but Hickey made a disclaimer upfront: this talk would be about what channels are and why Clojure has them, not the details of how they are implemented. Given that there were plenty of good compiler talks elsewhere at the conference, this was a welcome change of pace. It was also a valuable one, because many more people will benefit from what Hickey taught about program design than would have benefited from staring at screens full of Clojure macros. The issues here are important ones, and ones that few programmers understand very well.

The fundamental problem is this: Reactive programs need to be machines, but functions make bad machines. Even sequences of functions.

The typical solution to this problem these days is to decompose the system logic into a set of response handlers. Alas, this leads to callback hell, a modern form of spaghetti code. Why? Even though the logic has been decomposed into pieces, it is still "of a piece", essentially a single logical entity. When this whole is implemented across multiple handlers, we can't see it as a unit, or talk about it easily. We need to, though, because we need to design the state machine that it comprises.

Clojure's solution to the problem, in the form of core.async, is the channel. This is an implementation of Tony Hoare's communicating sequential process. One of the reasons that Hickey likes this approach is that it lets a program work equally well in fully threaded apps and in apps with macro-generated inversion of control.

Hickey then gave some examples of code using channels and talked a bit about the implications of the implementation for system design. For instance, the language provides handy put! and take! operators for integrating channels with code at the edge of non-core.async systems. I don't have much experience with Clojure, so I'll have to study a few examples in detail to really appreciate this.

For me, the most powerful part of the talk was an extended discussion of communication styles in program. Hickey focused on the trade-offs between direct communication via shared state and indirect communication via channels. He highlighted six or seven key distinctions between the two and how these affect the way a system works. I can't do this part of the talk justice, so I suggest you watch the video of the talk. I plan to watch it again myself.

I had always heard that Hickey was eminently quotable, and he did not disappoint. Here are three lines that made me smile:

  • "Friends don't let friends put logic in handlers."
  • "Promises and futures are the one-night stands" of asynchronous architecture.
  • "Unbounded buffers are a recipe for a bad program. 'I don't want to think about this bug yet, so I'll leave the buffer unbounded.'"

That last one captures the indefatigable optimism -- and self-delusion -- that characterizes so many programmers. We can fix that problem later. Or not.

In the end, this talk demonstrates how a good engineer approaches a problem. Clojure and its culture reside firmly in the functional programming camp. However, Hickey recognizes that, for the problem at hand, a sequence of functional calls is not the best solution. So he designs a solution that allows programmers to do FP where it fits best and to do something else where FP doesn't. That's a pragmatic way to approach problems.

Still, this solution is consistent with Clojure's overall design philosophy. The channel is a first-class object in the language. It converts a sequence of functional calls into data, whereas callbacks implement the sequence in code. As code, we see the sequence only at run-time. As data, we see it in our program and can use it in all the ways we can use any data. This consistent focus on making things into data is an attractive part of the Clojure language and the ecosystem that has been cultivated around it.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

September 27, 2013 4:26 PM

StrangeLoop: Add All These Things

[My notes on StrangeLoop 2013: Table of Contents]

I took a refreshing walk in the rain over the lunch hour on Friday. I managed to return late and, as a result, missed the start of Avi Bryant's talk on algebra and analytics. Only a few minutes, though, which is good. I enjoyed this presentation.

Bryant didn't talk about the algebra we study in eighth or ninth grade, but the mathematical structure math students encounter in a course called "abstract" or "modern" algebra. A big chunk of the talk focused on an even narrower topic: why +, and operators like it, are cool.

One reason is that grouping doesn't matter. You can add 1 to 2, and then add 4 to the result, and have the same answer as if you added 4 to 1, and then added 2 to the result. This is, of course, the associative property.

Another is that order doesn't matter. 1 + 2 is the same as 2 + 1. That's the commutative property.

Yet another is that, if you have nothing to add, you can add nothing and have the same value you started with. 4 + 0 = 4. 0 is the identity element for addition.

Finally, when you add two numbers, you get a number back. This is not quite as true in computers as in math, because an operation can cause an overflow or underflow and create an error. But looked at through fuzzy lenses, this is true in our computers, too. This is the closure property for addition of integers and real numbers.

Addition isn't the only operation on numbers that has these properties. Finding the maximum value in a set of numbers, does, too. The maximum of two numbers is a number. max(x,y) = max(y,x), and if we have three or more numbers, it doesn't how matter how we group them; max will find the maximum among them. The identity value is tricky -- there is no smallest number... -- but in practice we can finesse this by using the smallest number of a given data type, or even allowing max to take "nothing" as a value and return its other argument.

When we see a pattern like this, Bryant said, we should generalize:

  • We have a function f that takes two values from a set and produces another member of the same set.
  • The order of f's arguments doesn't matter.
  • The grouping of f's arguments doesn't matter.
  • There is some identity value, a conceptual "zero", that doesn't matter, in the sense that f(i,zero) for any i is simply i.

There is a name for this pattern. When we have such as set and operation, we have a commutative monoid.

     S ⊕ S → S
     x ⊕ y = y ⊕ x
     x ⊕ (y ⊕ z) = (x ⊕ y) ⊕ z
     x ⊕ 0 = x

I learned about this and other such patterns in grad school when I took an abstract algebra course for kicks. No one told me at the time that I'd being seeing them again as soon as someone created the Internet and it unleashed a torrent of data on everyone.

Just why we are seeing the idea of a commutative monoid again was the heart of Bryant's talk. When we have data coming into our company from multiple network sources, at varying rates of usage and data flow, and we want to extract meaning from the data, it can be incredibly handy if the meaning we hope to extract -- the sum of all the values, or the largest -- can be computed using a commutative monoid. You can run multiple copies of your function at the entry point of each source, and combine the partial results later, in any order.

Bryant showed this much more attractively than that, using cute little pictures with boxes. But then, there should be an advantage to going to the actual talk... With pictures and fairly straightforward examples, he was able to demystify the abstract math and deliver on his talk's abstract:

A mathematician friend of mine tweeted that anyone who doesn't understand abelian groups shouldn't build analytics systems. I'd turn that around and say that anyone who builds analytics systems ends up understanding abelian groups, whether they know it or not.

That's an important point. Just because you haven't studied group theory or abstract algebra doesn't mean you shouldn't do analytics. You just need to be prepared to learn some new math when it's helpful. As programmers, we are all looking for opportunities to capitalize on patterns and to generalize code for use in a wider set of circumstances. When we do, we may re-invent the wheel a bit. That's okay. But also look for opportunities to capitalize on patterns recognized and codified by others already.

Unfortunately, not all data analysis is as simple as summing or maximizing. What if I need to find an average? The average operator doesn't form a commutative monoid with numbers. It falls short in almost every way. But, if you switch from the set of numbers to the set of pairs [n, c], where n is a number and c is a count of how many times you've seen n, then you are back in business. Counting is addition.

So, we save the average operation itself as a post-processing step on a set of number/count pairs. This turns out to be a useful lesson, as finding the average of a set is a lossy operation: it loses track of how many numbers you've seen. Lossy operations are often best saved for presenting data, rather than building them directly into the system's computation.

Likewise, finding the top k values in a set of numbers (a generalized form of maximum) can be handled just fine as long as we work on lists of numbers, rather than numbers themselves.

This is actually one of the Big Ideas of computer science. Sometimes, we can use a tool or technique to solve a problem if only we transform the problem into an equivalent one in a different space. CS theory courses hammer this home, with oodles of exercises in which students are asked to convert every problem under the sun into 3-SAT or the clique problem. I look for chances to introduce my students to this Big Idea when I teach AI or any programming course, but the lesson probably gets lost in the noise of regular classwork. Some students seem to figure it out by the time they graduate, though, and the ones who do are better at solving all kinds of problems (and not by converting them all 3-SAT!).

Sorry for the digression. Bryant didn't talk about 3-SAT, but he did demonstrate several useful problem transformations. His goal was more practical: how can we use this idea of a commutative monoid to extract as many interesting results from the stream of data as possible.

This isn't just an academic exercise, either. When we can frame several problems in this way, we are able to use a common body of code for the processing. He called this body of code an aggregator, comprising three steps:

  • prepare the data by transforming it into the space of a commutative monoid
  • reduce the data to a single value in that space, using the appropriate operator
  • present the result by transforming it back into its original space

In practice, transforming the problem into the space of a monoid presents challenges in the implementation. For example, it is straightforward to compute the number of unique values in a collection of streams by transforming each item into a set of size one and then using set union as the operator. But union requires unbounded space, and this can be inconvenient when dealing with very large data sets.

One approach is to compute an estimated number of uniques using a hash function and some fancy arithmetic. We can make the expected error in estimate smaller and smaller by using more and more hash functions. (I hope to write this up in simple code and blog about it soon.)

Bryant looked at one more problem, computing frequencies, and then closed with a few more terms from group theory: semigroup, group, and abelian group. Knowing these terms -- actually, simply knowing that they exist -- can be useful even for the most practical of practitioners. They let us know that there is more out there, should our problems become harder or our needs become larger.

That's a valuable lesson to learn, too. You can learn all about abelian groups in the trenches, but sometimes it's good to know that there may be some help out there in the form of theory. Reinventing wheels can be cool, but solving the problems you need solved is even cooler.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Patterns, Software Development

September 22, 2013 3:51 PM

StrangeLoop: Jenny Finkel on Machine Learning at Prismatic

[My notes on StrangeLoop 2013: Table of Contents]

The conference opened with a talk by Jenny Finkel on the role machine learning play at Prismatic, the customized newsfeed service. It was a good way to start the conference, as it introduced a few themes that would recur throughout, had a little technical detail but not too much, and reported a few lessons from the trenches.

Prismatic is trying to solve the discovery problem: finding content that users would like to read but otherwise would not see. This is more than simply a customized newsfeed from a singular journalistic source, because it draws from many sources, including other reader's links, and because it tries to surprise readers with articles that may not be explicitly indicated by their profiles.

The scale of the problem is large, but different from the scale of the raw data facing Twitter, Facebook, and the like. Finkel said that Prismatic is processing only about one million timely docs at a time, with the set of articles turning over roughly weekly. The company currently uses 5,000 categories to classify the articles, though that number will soon go up to the order of 250,000.

The complexity here comes from the cross product of readers, articles, and categories, along with all of the features used to try to tease out why readers like the things they do and don't like the others. On top of this are machine learning algorithms that are themselves exponentially expensive to run. And with articles turning over roughly weekly, they have to be amassing data, learning from it, and moving on constantly.

The main problem at the heart of a service like this is: What is relevant? Everywhere one turns in AI, one sees this question, or its more general cousin, Is this similar? In many ways, this is the problem at the heart of all intelligence, natural and artificial.

Prismatic's approach is straight from AI, too. They construct a feature vector for each user/article pair and then try to learn weights that, when applied to the values in a given vector, will rank desired articles high and undesired articles low. One of the key challenges when doing this kind of working is to choose the right features to use in the vector. Finkel mentioned a few used by Prismatic, including "Does the user follow this topic?", "How many times has the reader read an article from this publisher?", and "Does the article include a picture?"

With a complex algorithm, lots of data, and a need to constantly re-learn, Prismatic has to make adjustments and take shortcuts wherever possible in order to speed up the process. This is a common theme at a conference where many speakers are from industry. First, learn your theory and foundations; learn the pragmatics and heuristics need to turn basic techniques into the backbone of practical applications.

Finkel shared one pragmatic idea of this sort that Prismatic uses. They look for opportunities to fold user-specific feature weights into user-neutral features. This enables their program to compute many user-specific dot products using a static vector.

She closed the talk with five challenges that Prismatic has faced that other teams might be on the look out for:

Bugs in the data. In one case, one program was updating a data set before another program could take a snapshot of the original. With the old data replaced by the new, they thought their ranker was doing better than it actually was. As Finkel said, this is pretty typical for an error in machine learning. The program doesn't crash; it just gives the wrong answer. Worse, you don't even have reason to suspect something is wrong in the offending code.

Presentation bias. Readers tend to look at more of the articles at the top of a list of suggestions, even if they would have enjoyed something further down the list. This is a feature of the human brain, not of computer programs. Any time we write programs that interact with people, we have to be aware of human psychology and its effects.

Non-representative subsets. When you are creating a program that ranks things, its whole purpose is to skew a set of user/article data points toward the subset of articles that the reader most wants to read. But this subset probably doesn't have the same distribution as the full set, which hampers your ability to use statistical analysis to draw valid conclusions.

Statistical bleeding. Sometimes, one algorithm looks better than it is because it benefits from the performance of the other. Consider two ranking algorithms, one an "explorer" that seeks out new content and one an "exploiter" that recommend articles that have already been found to be popular. If we in comparing their performances, the exploiter will tend to look better than it is because it benefits from the successes of the explorer without being penalized for its failures. It is crucial to recognize that one feature you measure is not dependent on another. (Thanks to Christian Murphy for the prompt!)

Simpson's Paradox. The iPhone and the web have different clickthrough rates. They once found them in a situation where one recommendation algorithm performed worse than another on both platforms, yet better overall. This can really disorient teams who follow up experiments by assessing the results. The issue here is usually a hidden variable that is confounding the results.

(I remember discussing this classic statistical illusion with a student in my early years of teaching, when we encountered a similar illusion in his grade. I am pretty sure that I enjoyed our discussion of the paradox more than he did...)

This part of a talk is of great value to me. Hearing about another team's difficulties rarely helps me avoid the same problems in my own projects, but it often does help me recognize those problems when they occur and begin thinking about ways to work around them. This was a good way for me to start the conference.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Patterns, Software Development

September 10, 2013 3:40 PM

A Laugh at My Own Expense

This morning presented a short cautionary tale for me and my students, from a silly mistake I made in a procmail filter.

Back story: I found out recently that I am still subscribed to a Billy Joel fan discussion list from the 1990s. The list has been inactive for years, or I would have been filtering its messages to a separate mailbox. Someone has apparently hacked the list, as a few days ago it started spewing hundreds of spam messages a day.

I was on the road for a few days after the deluge began and was checking mail through a shell connection to the mail server. Because I was busy with my trip and checking mail infrequently, I just deleted the messages by hand. When I got back, Mail.app soon learned they were junk and filtered them away for me. But the spam was still hitting my inbox on the mail server, where I read my mail occasionally even on campus.

After a session on the server early this morning, I took a few minutes to procmail them away. Every message from the list has a common pattern in the Subject: line, so I copied it and pasted it into a new procmail recipe to send all list traffic to /dev/null :

    :0
    * ^Subject.*[billyjoel]
    /dev/null

Do you see the problem? Of course you do.

I didn't at the time. My blindness probably resulted from a combination of the early hour, a rush to get over to the gym, and the tunnel vision that comes from focusing on a single case. It all looked obvious.

This mistake offers programming lessons at several different levels.

The first is at the detailed level of the regular expression. Pay attention to the characters in your regex -- all of them. Those brackets really are in the Subject: line, but by themselves mean something else in the regex. I need to escape them:

    * ^Subject.*\[billyjoel\]

This relates to a more general piece of problem-solving advice. Step back from individual case you are solving and think about the code you are writing more generally. Focused on the annoying messages from the list, the brackets are just characters in a stream. Looked at from the perspective of the file of procmail recipes, they are control characters.

The second is at the level of programming practice. Don't /dev/null something until you know it's junk. Much better to send the offending messages to a junk mbox first:

    * ^Subject.*\[billyjoel\]
    in.tmp.junk

Once I see that all and only the messages from the list are being matched by the pattern, I can change that line send list traffic where it belongs. That's a specific example of the sort of defensive programming that we all should practice. Don't commit to solutions too soon.

This, too, relates to more general programming advice about software validation and verification. I should have exercised a few test cases to validate my recipe before turning it loose unsupervised on my live mail stream.

I teach my students this mindset and program that way myself, at least most of the time. Of course, the time you most need test cases will be the time you don't write them.

The day provided a bit of irony to make the story even better. The topic of today's session in my compilers course? Writing regular expressions to describe the tokens in a language. So, after my mail admin colleague and I had a good laugh at my expense, I got to tell the story to my students, and they did, too.


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

September 05, 2013 3:13 PM

Code Should Speak for Itself

Matt Welsh recently posted a blog entry on experiences rewriting a large system in Go and some of his thoughts about the language afterwards. One of the few shortcomings in his mind had to do with how Go's type inference made it hard for him to know the type of a variable. Sure, an IDE or other tool could help, but Welsh says:

I staunchly refuse to edit code with any tool that requires using a mouse.

That's mostly how I feel, too, though I'm more an emacs man. I use IDEs and appreciate what they can give. I used Eclipse a fair amount back when it was young, but it's gotten so big and complex these days that I shudder at the thought of starting it up. RubyMine gave me many pleasant moments when I used it for a while a couple of years ago.

When I use IDEs, I prefer simpler IDEs, such as Dr. Racket or even Dr. Java, to complex ones anyway. They don't generally provide as much support, but they do help. When not helping, they mostly staying out of the way while I am writing code.

For me, the key word in Welsh's refusal is require'. If I *need* a mouse or a lot of IDE support just to use a language, that's a sign that the code either isn't telling me everything it should, or there's too much to think about.

Code should speak for itself, and it only say things that the programmer needs to know.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

August 31, 2013 11:32 AM

A Good Language Conserves Programmer Energy

Game programmer Jeff Wofford wrote a nice piece on some of the lessons he learned by programming a game in forty-eight hours. One of the recurring themes of his article is the value of a high-powered scripting language for moving fast. That's not too surprising, but I found his ruminations on this phenomenon to be interesting. In particular:

A programmer's chief resource is the energy of his or her mind. Everything that expends or depletes that energy makes him or her less effective, more tired, and less happy.

A powerful scripting language sitting atop the game engine is one of the best ways to conserve programmer energy. Sometimes, though, a game programmer must work hard to achieve the performance required by users. For this reason, Wofford goes out of his way not to diss C++, the tool of choice for many game programmers. But C++ is an energy drain on the programmer's mind, because the programmer has to be in a constant state of awareness of machine cycles and memory consumption. This is where the trade-off with a scripting language comes in:

When performance is of the essence, this state of alertness is an appropriate price to pay. But when you don't have to pay that price -- and in every game there are systems that have no serious likelihood of bottlenecking -- you will gain mental energy back by essentially ignoring performance. You cannot do this in C++: it requires an awareness of execution and memory costs at every step. This is another argument in favor of never building a game without a good scripting language for the highest-level code.

I think this is true of almost every large system. I sure wish that the massive database systems at the foundation of my university's operations had scripting languages sitting on top. I even want to script against the small databases that are the lingua franca of most businesses these days -- spreadsheets. The languages available inside the tools I use are too clunky or not powerful, so I turn to Ruby.

Unfortunately, most systems don't come with a good scripting language. Maybe the developers aren't allowed to provide one. Too many CS grads don't even think of "create a mini-language" as a possible solution to their own pain.

Fortunately for Wofford, he both has the skills and inclination. One of his to-dos after the forty-eight hour experience is all about language:

Building a SWF importer for my engine could work. Adding script support to my engine and greatly refining my tools would go some of the distance. Gotta do something.

Gotta do something.

I'm teaching our compiler course again this term. I hope that the dozen or so students in the course leave the university knowing that creating a language is often the right next action and having the skills to do it when they feel compelled to do something.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

August 22, 2013 2:45 PM

A Book of Margin Notes on a Classic Program?

I recently stumbled across an old How We Will Read interview with Clive Thompson and was intrigued by his idea for a new kind of annotated book:

I've had this idea to write a provocative piece, or hire someone to write it, and print it on-demand it with huge margins, and then send it around to four people with four different pens -- red, blue, green and black. It comes back with four sets of comments all on top of the text. Then I rip it all apart and make it into an e-book.

This is an interesting mash-up of ideas from different eras. People have been writing in the margins of books for hundreds of years. These days, we comment on blog entries and other on-line writing in plain view of everyone. We even comment on other people's comments. Sites such as Findings.com, home of the Thompson interview, aim to bring this cultural practice to everything digital.

Even so, it would be pretty cool to see the margin notes of three or four insightful, educated people, written independently of one another, overlaid in a single document. Presentation as an e-book offers another dimension of possibilities.

Ever the computer scientist, I immediately began to think of programs. A book such as Beautiful Code gives us essays from master programmers talking about their programs. Reading it, I came to appreciate design decisions that are usually hidden from readers of finished code. I also came to appreciate the code itself as a product of careful thought and many iterations.

My thought is: Why not bring Thompson's mash-up of ideas to code, too? Choose a cool program, perhaps one that changed how we work or think, or one that unified several ideas into a standard solution. Print it out with huge margins, and send it to three of four insightful, thoughtful programmers who read it, again or for the first time, and mark it up with their own thoughts and ideas. It comes back with four sets of comments all on top of the text. Rip it apart and create an e-book that overlays them all in a single document.

Maybe we can skip the paper step. Programming tools and Web 2.0 make it so easy to annotate documents, including code, in ways that replace handwritten comments. That's how most people operate these days. I'm probably showing my age in harboring a fondness for the written page.

In any case, the idea stands apart from the implementation. Wouldn't it be cool to read a book that interleaves and overlays the annotations made by programmers such as Ward Cunningham and Grady Booch as they read John McCarthy's first Lisp interpreter, the first Fortran compiler from John Backus's team, QuickDraw, or Qmail? I'd stand in line for a copy.

Writing this blog entry only makes the idea sound more worth doing. If you agree, I'd love to hear from you -- especially if you'd like to help. (And especially if you are Ward Cunningham and Grady Booch!)


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

August 13, 2013 3:11 PM

Refactoring is Underrated

I think revision is hugely underrated. It is very seldom recognized as a place where the higher creativity can live, or where it can manifest. I think it was Yeats who said that literary revision was the only place in life where a man could truly improve himself.

-- William Gibson, The Art of Fiction No. 211

I find it a lot easier to come up with clean, simple designs when I have code in my hands to work with, rather than requirements. Even detailed requirements are abstract with respect to our programs. Code is the raw material.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

July 25, 2013 10:01 AM

Software is Hard...

... but here I am, writing another program.

She could feel her own lungs suspended as she worked, and she forced herself to inhale, suddenly frustrated by the insurmountable inability to make the paint correspond exactly and precisely to what was in her head. It was always doomed from the outset, but here she was, making another goddamned painting.

(From The Great Man, by Kate Christensen.)


Posted by Eugene Wallingford | Permalink | Categories: Software Development

July 03, 2013 10:22 AM

Programming for Everyone, Venture Capital Edition

Christina Cacioppo left Union Square Ventures to learn how to program:

Why did I want to do something different? In part, because I wanted something that felt more tangible. But mostly because the story of the internet continues to be the story of our time. I'm pretty sure that if you truly want to follow -- or, better still, bend -- that story's arc, you should know how to write code.

So, rather than settle for her lot as a non-programmer, beyond the accepted school age for learning these things -- technology is a young person's game, you know -- Cacioppo decided to learn how to build web apps. And build one.

When did we decide our time's most important form of creation is off-limits? How many people haven't learned to write software because they didn't attend schools that offered those classes, or the classes were too intimidating, and then they were "too late"? How much better would the world be if those people had been able to build their ideas?

Yes, indeed.

These days, she is enjoying the experience of making stuff: trying ideas out in code, discarding the ones that don't work, and learning new things every day. Sounds like a programmer to me.


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

June 26, 2013 2:30 PM

An Opportunity to Learn, Born of Deprivation

Earlier this summer, my daughter was talking about something one of her friends had done with Instagram. As a smug computer weenie, I casually mentioned that she could do that, too.

She replied, "Don't taunt me, Dad."

You see, no one in our family has a cell phone, smart or otherwise, so none of us use Instagram. That's not a big deal for dear old dad, even though (or perhaps because) he's a computer scientist. But she is a teenager growing up in an entirely different world, filled with technology and social interaction, and not having a smart phone must surely seem like a form of child abuse. Occasionally, she reminds us so.

This gave me a chance to explain that Instagram filters are, at their core, relatively simple little programs, and that she could learn to write them. And if she did, she could run them on almost any computer, and make them do things that even Instagram doesn't do.

I had her attention.

So, this summer I am going to help her learn a little Python, using some of the ideas from media computation. At the end of our first pass, I hope that she will be able to manipulate images in a few basic ways: changing colors, replacing colors, copying pixels, and so on. Along the way, we can convert color images to grayscale or sepia tones, posterize images, embed images, and make simple collages.

That will make her happy. Even if she never feels the urge to write code again, she will know that it's possible. And that can be empowering.

I have let my daughter know that we probably will not write code that does as good a job as what she can see in Instagram or Photoshop. Those programs are written by pros, and they have evolved over time. I hope, though, that she will appreciate how simple the core ideas are. As James Hague said in a recent post, then key idea in most apps require relatively few lines of code, with lots and lots of lines wrapped around them to handle edge cases and plumbing. We probably won't write much code for plumbing... unless she wants to.

Desire and boredom often lead to creation. They also lead to the best kind of learning.


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

June 25, 2013 2:46 PM

Data Ingestion

This sentence in Reid Draper's Data Traceability made me laugh recently:

I previously worked in the data ingestion team at a music data company.

Nice turn of phrase. I suppose that another group digests the data, and yet another expels it.

Draper's sentence came to mind again yesterday while I was banging my head on a relatively simple problem, transforming a CSV file generated by my university's information system, replete with embedded quotes and commas, into something more manageable. As data ingestion goes, this isn't much of a problem at all. There are plenty of libraries that do the heavy lifting for you, in most any language you choose, Ruby included.

Of course, I was just writing a quick-and-dirty script, so I was rolling my own CSV-handling code. As usual, "quick and dirty" is often dirty, but rarely quick. I tweeted a bit of my frustration, in response to which @geoffwozniak wrote:

Welcome to the world of enterprise data ingress.

If I had to deal with these files everyday, I might head for the egress. ... or master a good library, so that I could bang my head on more challenging data ingestion problems.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

June 20, 2013 12:32 PM

Agile Moments: Stories, Tests, and Refactoring in Visual Design

In A Place for Sharing Ideas and Stories, designers Teehan+Lax tell the story of their role in creating Medium, "a better place to read and write things that matter". The section "Forging ahead", about features added to the platform after its launch, made me think of some of the ideas we use when designing code test-first, only at a much higher level.

We reset by breaking the team up into new feature teams. Each feature team would have at least one designer, one front-end developer and a back-end developer. Some teams would take on multiple features depending on their complexity. We used one page briefs that were easy to write, easy to understand and helped guide the teams when working through their feature(s).

They consisted of questions like:

  • Who is this page for?
  • What problem does this page solve for the user?
  • How do we know they need it?
  • What is the primary action we want users to take on this page?
  • What might prompt a user to take this action?
  • How will we know that this page is doing what we want it to do?

This bullet list embodies several elements of agile development. For each feature, the brief acts like a story card that boils the feature down to a clear need of the user, a clear action, and, most important in my mind, a test: How will we know that this page is doing what we want it to do? In a lot of my work, this is a crucial element. As Kent Beck says, "How will I know I'm done?"

The paragraph preceding the list highlights a couple of other attributes common to agile development. One, teams are working on stories in parallel on a common artifact. Two, the teams include a designer, a front-end developer, and a back-end developer. The team doesn't include a user, which can be a huge advantage for developers, but the author mentions elsewhere that nearly everyone on the team was a user:

As the internal product progressed and its features and capabilities became clearer, we would reduce the amount of ad hoc meetings and focus on getting stuff built into the product so we could actually use it. Talking about work is great at first, but usage is what breathes life into the product.

The author also stresses the value of physical co-location of the designers and developers over even well-supported electronic communication, which echoes for me the value of having a user in the room with the developers.

What happens as features were enhanced or added by separate teams? "... maintaining some sort of design integrity across the entire product."

This thing was about to get full of user choices (read: complexity) in a hurry -- The product was now at a critical point in its life.

Of course, complexity and incoherence can creep into products even when they are designed and built by one team, when it works on multiple features in rapid succession.

The solution for Medium sounded familiar:

We took a week off current fixes and features and focused on redesigning three pages from scratch: Home, Collection and Post. Some of it went live, some of it went away.

And:

We hated to see some of the stuff we'd designed (and even built) not go live, but it needed to die so the product could grow through simplification.

This reminded me a lot like refactoring, even with differences from the way we refactor at the code level. As teams added features without considering the effect of the changes on the global structure of the product, they accumulated something akin to "design debt". So after a while they dedicated time to paying off the debt and bringing back to the product the sense of wholeness that had been lost. I am curious to know whether the teams ever looked back at the page briefs to verify that the redesigned pages still did what they wanted them to do. That would be the equivalent of "running the tests".

We programmers really do have it nice. Lines and units of code are a bit more separable than the visual design elements of a product. This allows us to refactor all the time, if we are so inclined, not just in batch after a large set of changes. The presence of concrete tests, written as code, allows us to test the efficacy of our changes relatively easily before we move forward. While down in the trenches writing code, it's easy to forget just how liberating -- and empowering -- this combination of separability and testability are for design and redesign.

It's also easy to forget sometimes that similar challenges face designers and creators across domains and disciplines. Many of the same themes run through stories the things we create, whether software in the small, software in the large, or physical artifacts. Reading Teahan+Lax's story reminded me of that, too.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

May 28, 2013 2:57 PM

The Willingness to Delete Working Code

Don DeLillo

... and to do code katas, too:

I find I'm more ready to discard pages than I used to be. I used to look for things to keep. I used to find ways to save a paragraph or a sentence, maybe by relocating it. Now I look for ways to discard things. If I discard a sentence I like, it's almost as satisfying as keeping a sentence I like. I don't think I've become ruthless or perverse--just a bit more willing to believe that nature will restore itself. The instinct to discard is finally a kind of faith. It tells me there's a better way to do this page even though the evidence is not accessible at the present time.

Says Don DeLillo, in The Art of Fiction No. 135. Even in programming, the willingness to cut a chunk of working code, or to rm -f a file, generally follows from a deep-seated belief that nature will restore itself. We are often happy to find that nature does a better job the second time around.

~~~

PHOTO: Adapted from http://www.flickr.com/photos/thousandrobots/5371974016/, (CC BY-SA 2.0).


Posted by Eugene Wallingford | Permalink | Categories: Software Development

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 hadrosaurus, which once roamed the land with legacy CS profs

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.


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

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.


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

April 30, 2013 4:53 PM

Exceleration

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.


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

April 25, 2013 4:03 PM

Toward a Course on Reading Code

Yesterday, I tweeted absent-mindedly:

It would be cool to teach a course called "Reading Code".

Reading code has been on mind for a few months now, as I've watched my students read relatively small pieces of code in my Programming Languages course and as I've read a couple of small libraries while reading the exercise bike. Then I ran across John Regehr's short brainstorm on the topic, and something clicked. So I tweeted.

Reading code, or learning to do it, must be on the minds of a lot people, because my tweet elicited quite a few questions and suggestions. It is an under-appreciated skill. Computer science programs rarely teach students how to do it, and then usually only implicitly, by hearing a prof or other students talk about code they've read.

Several readers wanted to know what the course outline would be. I don't know. That's one of the things about Twitter or even a blog: it is easy to think out loud absent-mindedly without having much content in mind yet. It's also easier to express an interest in teaching a course than to design a good one.

Right now, I have only a few ideas about how I'd start. Several readers suggested Code Reading by Spinellis, which is the only textbook I know on then topic. It may be getting a little old these days, but many of the core techniques are still sound.

I was especially pleased that someone recommended Richard Gabriel's idea for an MFA in Software, in which reading plays a big role. I've used some of Dick's ideas in my courses before. Ironically, the last time I mentioned the MFA in Software idea in my blog was in the context of a "writing code" course, at the beginning of a previous iteration of Programming Languages!

That's particularly funny to me because someone replied to my tweet about teaching a course called "Reading Code" with:

... followed by a course "Writing Readable Code".

Anyone who has tried to grade thirty evolving language interpreters each week appreciates this under-appreciated skill.

Chris Demwell responded to my initial tweet with direct encouragement: Write the course, or at least an outline, and post it. I begged indulgence for lack of time as the school year ends and said that maybe I can take a stab this summer. Chris's next tweet attempted to pull me into the 2010s:

1. Write an outline. 2. Post on github. 3. Accept pull requests. Congrats, you're an editor!

The world has indeed changed. This I will do. Watch for more soon. In the meantime, feel free to e-mail me your suggestions. (That's an Old School pull request.)


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

April 09, 2013 3:16 PM

Writing a Book Is Like Flying A Spaceship

I've always liked this quote from the preface of Pragmatic Ajax, by Gehtland, Galbraith, and Almaer:

Writing a book is a lot like (we imagine) flying a spaceship too close to a black hole. One second you're thinking "Hey, there's something interesting over there," and a picosecond later, everything you know and love has been sucked inside and crushed.

Programming can be like that, too, in a good way. Just be sure to exit the black hole on the other side.


Posted by Eugene Wallingford | Permalink | Categories: General, Software Development

April 01, 2013 3:16 PM

Good Sentences, Programming State Edition

I've read a couple of interesting papers recently that included memorable sentences related to program state.

First, Stuart Sierra in On the Perils of Dynamic Scope:

Global state is the zombie in the closet of every Clojure program.

This essay explains the difference between scope and extent, a distinction that affects how easy it is to some of what happens in a program with closures and first-order functions with free variables. Sierra also shows the tension between variables of different kinds, using examples from Clojure. An informative read.

Next, Rob Pike in Go at Google: Language Design in the Service of Software Engineering, a write-up of his SPLASH 2012 keynote address:

The motto [of the Go language] is, "Don't communicate by sharing memory, share memory by communicating."

Imperative programmers who internalize this simple idea are on their way to understanding and using functional programming style effectively. The inversion of sharing and communication turns a lot of design and programming patterns inside out.

Pike's notes provide a comprehensive example of how a new language can grow out of the needs of a particular set of applications, rather than out of programming language theory. The result can look a little hodgepodge, but using such a language often feels just fine. (This reminds me of a different classification of languages with similar practical implications.)

~~~~

(These papers weren't published April Fool's Day, so I don't think I've been punked.)


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

March 27, 2013 12:46 PM

Programming Language as Operating System

We are deep in the semester now, using Racket in our programming languages course. I was thinking recently about how little of Racket's goodness we use in this course. We use it primarily as a souped-up R5RS Scheme and handy IDE. Tomorrow we'll see some of Racket's tools for creating new syntax, which will explore one of the rich niches of the system my students haven't seen yet.

I'm thinking about ways to introduce a deeper understanding of The Racket Way, in which domain concepts are programming language constructs and programming languages are extensible and composable. But it goes deeper. Racket isn't just a language, or a set of languages. It is an integrated family of tools to support language creation and use. To provide all these services, Racket acts like an operating system -- and gives you full programmatic access to the system.

(You can watch the video of Flatt's StrangeLoop talk "The Racket Way" at InfoQ -- and you should.)

The idea is bigger than Racket, of course. Dan Ingalls expressed this idea in his 1981 Byte article, Design Principles Behind Smalltalk:

Operating System: An operating system is a collection of things that don't fit into a language. There shouldn't be one.

Alan Kay talks often about this philosophy. The divide between programming language and operating system makes some things more difficult for programmers, and complicates the languages and tools we use. It also creates a divide in the minds of programmers and imposes unnecessary limitations on what programmers think is possible. One of things that appealed to me in Flatt's StrangeLoop talk is that presented a vision of programming without those limits.

There are implications of this philosophy, and costs. Smalltalk isn't just a language, with compilers and tools that you use at your Unix prompt. It's an image, and a virtual machine, and an environment. You don't use Smalltalk; you live inside it.

After you live in Smalltalk for a while, it feels strange to step outside and use other languages. More important, when you live outside Smalltalk and use traditional languages and tools, Smalltalk feels uncomfortable at best and foreboding at worst. You don't learn Smalltalk; you assimilate. -- At least that's what it feels like to many programmers.

But the upside of the "programming language as operating system" mindset you find in Smalltalk and Racket can be huge.

This philosophy generalizes beyond programming languages. emacs is a text editor that subsumes most everything else you do, if you let it. (Before I discovered Smalltalk in grad school, I lived inside emacs for a couple of years.)

You can even take this down to the level of the programs we write. In a blog entry on delimited continuations, Andy Wingo talks about the control this construct gives the programmer over how their programs work, saying:

It's as if you were implementing a shell in your program, as if your program were an operating system for other programs.

When I keep seeing the same idea pop up in different places, with a form that fits the niche, I'm inclined to think I am seeing one of the Big Ideas of computer science.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

March 22, 2013 9:17 AM

Honest Answers: Learning APL

After eighteen printed pages showing the wonders of APL in A Glimpse of Heaven, Bernard Legrand encourages programmers to give the language a serious look. But he cautions APL enthusiasts not to oversell the ease of learning the language:

Beyond knowledge of the basic elements, correct APL usage assumes knowledge of methods for organising data, and ways specific to APL, of solving problems. That cannot be learnt in a hurry, in APL or any other language.

Legrand is generous in saying that learning APL takes the same amount of time as learning any other language. In my experience, both as a learning of language and as a teacher of programmers, languages and programming styles that are quite different from one's experience take longer than more familiar topics. APL is one of those languages that requires us to develop entirely new ways of thinking about data and process, so it will take most people longer to learn than yet another C-style imperative language or OO knock-off.

But don't be impatient. Wanting to move too quickly is a barrier to learning and performing at all scales, and too often leads us to give up too soon. If you give up on APL too soon, or on functional programming, or OOP, you will never get to glimpse the heaven that experienced programmers see.


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

March 11, 2013 4:25 PM

Does Readability Give a False Sense of Understandability?

In Good for Whom?, Daniel Lyons writes about the readability of code. He starts with Dan Ingall's classic Design Principles Behind Smalltalk, which places a high value on a system being comprehensible by a single person, and then riffs on readability in J and Smalltalk.

Early on, Lyons made me smile when he noted that, while J is object-oriented, it's not likely to be used that way by many people:

... [because] to use advanced features of J one must first use J, and there isn't a lot of that going on either.

As a former Smalltalker, I know how he feels.

Ultimately, Lyons is skeptical about claims that readability increases the chances that a language will attract a large audience. For one thing, there are too many counterexamples in both directions. Languages like C, which "combines the power of assembly language with the readability of assembly language" [ link ], are often widely used. Languages such as Smalltalk, Self, and Lisp, which put a premium on features such as purity and factorability, which in turn enhance readability, never seem to grow beyond a niche audience.

Lyons's insight is that readability can mislead. He uses as an example the source code of the J compiler, which is written in C but in a style mimicking J itself:

So looking at the J source code, it's easy for me to hold my nose and say, that's totally unreadable garbage; how can that be maintained? But at the same time, it's not my place to maintain it. Imagine if it were written in the most clean, beautiful C code possible. I might be able to dupe myself into thinking I could maintain it, but it would be a lie! Is it so bad that complex projects like J have complex code? If it were a complex Java program instead, I'd still need substantial time to learn it before I would stand a chance at modifying it. Making it J-like means I am required to understand J to change the source code. Wouldn't I have to understand J to change it anyway?

There is no point in misleading readers who have trouble understanding J-like code into thinking they understand the compiler, because they don't. A veneer of readability cannot change that.

I know how Lyons feels. I sometimes felt the same way as I learned Smalltalk by studying the Smalltalk system itself. I understood how things worked locally, within a method and then within a class, but I didn't the full network of classes that made up the system. And I had the scars -- and trashed images -- to prove it. Fortunately, Smalltalk was able to teach me many things, including object-oriented programming, along the way. Eventually I came to understand better, if not perfectly, how Smalltalk worked down its guts, but that took a lot of time and work. Smalltalk's readability made the code accessible to me early, but understanding still took time.

Lyons's article brought to mind another insight about code's understandability that I blogged about many years ago in an entry on comments in code. This insight came from Brian Marick, himself no stranger to Lisp or Smalltalk:

[C]ode can only ever be self-explanatory with respect to an expected reader.

Sometimes, perhaps it's just as well that a language or a program not pretend to be more understandable than it really is. Maybe a barrier to entry is good, by keeping readers out until they are ready to wield the power it affords.

If nothing else, Lyons's stance can be useful as a counterweight to an almost unthinking admiration of readable syntax and programming style.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

March 08, 2013 3:50 PM

Honest Answers: Debugging

We have all been there:

Somehow, at some point in every serious programming project, it always comes down to the last option: stare at the code until you figure it out. I wish I had a better answer, but I don't. Anyway, it builds character.

This is, of course, the last resort. We need to teach students better ways to debug before they have to fall back on what looks a lot like wishful thinking. Fortunately, John Regehr lists this approach as the last resort in his lecture on How to Debug. Before he tells students to fall back to the place we all have to fall back to occasionally, he outlines an explicit, evidence-driven process for finding errors in a program.

I like that Regehr includes this advice for what to do after you find a bug: step back and figure out what error in thinking led to the bug.

An important part of learning from a mistake is diagnosing why you made it, and then taking steps wherever possible to make it difficult or impossible to make the same mistake again. This may involve changing your development process, creating a new tool, modifying an existing tool, learning a new technique, or some other act. But it requires an act. Learning rarely just happens.


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

March 07, 2013 3:31 PM

A Programming Koan

Student: "I didn't have time to write 150 lines of code for the homework."

Master: "That's fine. It requires only 50."

Student: "Which 50?"

I have lived this story several times recently, as the homework in my Programming Languages has become more challenging. A few students do not complete the assignment because they do not spend enough time on the course, either in practice or performance. But most students do spend enough time, both in practice and on the assignment. Indeed, they spend much more time on the assignment than I intend.

When I see their code, I know why. They have written long solutions: code with unnecessary cases, unnecessary special cases, and unnecessary helper functions. And duplication -- lots and lots of duplication. They run out of time to write the ten lines they need to solve the last problem on the set because they spent all their time writing thirty lines on each of the preceding problems, where ten would have done quite nicely.

Don't let anyone fool you. Students are creative. The trick is o help them harness their creativity for good. The opposite of good here is not evil, but bad code -- and too much code.


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

February 27, 2013 11:52 AM

Programming, Writing, and Clear Thinking

This Fortune Management article describes a technique Jeff Bezos uses in meetings of his executive team: everyone begins by "quietly absorbing ... six-page printed memos in total silence for as long as 30 minutes".

There is a good reason, Bezos knows, for an emphasis on reading and the written word:

There is no way to write a six-page, narratively structured memo and not have clear thinking.

This is certainly true for programming, that unique form of writing that drives the digital world. To write a well-structured, six-page computer program to perform a task, you have to be able to think clearly about your topic.

Alas, the converse is not true, at least not without learning some specific skills and practicing a lot. But then again, that makes it just like writing narratives.

My Programming Languages students this semester are learning that, for functional programming in Scheme, the size limit is somewhat south of six pages. More along the lines of six lines.

That's a good thing if your goal is clear thinking. Work hard, clarify your thoughts, and produce a small function that moves you closer to your goal. It's a bad thing if your goal is to get done quickly.


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

February 25, 2013 4:07 PM

Thelonious Monk Teaches Software Design

Thelonious Monk at the piano

Thelonious Monk was a cool cat on the piano, but I think he could feel at home as a programmer. For example:

The _inside_ of the tune is the part that makes the _outside_ sound good.

Monk would understand that the design of your code matters as much as the design of your program's user interface. That is certainly true for developers who will have to maintain and modify the code over time. But it is also true for your program's users. It's hard for a program to be well designed on the outside, however pretty, when it is poorly designed on the inside.

Don't play _everything_ (or every time); let some things go by. Some music is just _imagined_. What you _don't_ play can be more important than what you _do_ play.

Some of the most effective software design happens in the negative space around software components. Alan Kay's original notions for designing objects stressed the messages that pass between objects more than the objects themselves. When we unfocus our eyes a bit and look at our system as a whole, the parts you don't design can come into focus.

a freehand rendition of the Japanese character 'ma'

And like Monk's missing notes, the code you don't write can be as important as the code you do, or more. The You Aren't Gonna Need It mindset tells us not to solve problems that don't exist yet. Live in the current spec. The result will be a minimal system, in terms of code size, with maximal effect.

You've got to dig it to _dig_ it, you dig?

A lot of people don't dig XP. But that's because they don't _dig_ it, you dig? Sometimes it takes surrendering old habits and thought processes all the way, pulling on a whole new way of approaching music or software, and letting it seep into your being for a while before you can really dig it. Some people begin skeptical but come to dig it after immersion.

This is true for a lot of practices that seem unusual or awkward, not just XP. As Alan Kay is also fond of saying, "Don't dip your toe in the water. Get wet."

~~~~

The quotes above are from a document archived by Steve Lacy, by way of Lists of Note.

PHOTO. Thelonious Monk, circa 1947 by William P. Gottlieb. Source: Wikipedia.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

February 19, 2013 3:36 PM

The Lumbering Lethargy of Software Engineering

Graham Lee makes an ironic observation in Does the history of making software exist?:

"[S]oftware engineering" ... was introduced to suggest a professionalism beyond the craft discipline that went before it, only to become a symbol of lumbering lethargy among adherents of the craft discipline that came after it.

It's funny how terms evolve and communities develop sometimes.

There are a lot of valuable lessons to be learned from the discipline of software engineering. As a mindset, it can shape how we build systems with good results. Taken too far, it can be a mindset can stifles and overloads the process of making software.

As a university professor, I have to walk a fine line, exposing students to the valuable lessons without turning the creation of software into a lethargic, lumbering process. My courses tend to look different from similar courses taught by software engineering profs. I presume that they feel different to students.

As a programmer, I walk a fine line, too, trying to learn valuable lessons from wherever I can. Often that's from the software engineering community. But I don't want to fall into a mindset where the process becomes more important than the result.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

February 18, 2013 12:59 PM

Code Duplication as a Hint to Think Differently

Last week, one of my Programming Languages students sent me a note saying that his homework solution worked correctly but that he was bothered by some duplicated code.

I was so happy.

Any student who has me for class for very long hears a lot about the dangers of duplication for maintaining code, and also that duplication is often a sign of poor design. Whenever I teach OOP or functional programming, we learn ways to design code that satisfy the DRY principle and ways to eliminate it via refactoring when it does sneak in.

I sent the student an answer, along with hearty congratulations for recognizing the duplication and wanting to eliminate it. My advice

When I sat down to blog the solution, I had a sense of deja vu... Hadn't I written this up before? Indeed I had, a couple of years ago: Increasing Duplication to Eliminate Duplication. Even in the small world of my own teaching, it seems there is nothing new under the sun.

Still, there was a slightly different feel to the way I talked about this in class later that day. The question had come earlier in the semester this time, so the code involved was even simpler. Instead of processing a vector or a nested list of symbols, we were processing with a flat list of symbols. And, instead of applying an arbitrary test to the list items, we were simply counting occurrences of a particular symbol, s.

The duplication occurred in the recursive case, where the procedure handles a pair:

    (if (eq? s (car los))
        (+ 1 (count s (cdr los)))      ; <---
        (count s (cdr los)))           ; <---

Then we make the two sub-cases more parallel:

    (if (eq? s (car los))
        (+ 1 (count s (cdr los)))      ; <---
        (+ 0 (count s (cdr los))))     ; <---

And then use distributivity to push the choice down a level:

    (+ (if (eq? s (car los)) 1 0)
       (count s (cdr los)))            ; <--- just once!

This time, I made a point of showing the students that not only does this solution eliminate the duplication, it more closely follows the command to follow the shape of the data:

When defining a program to process an inductively-defined data type, the structure of the program should follow the structure of the data.

This guideline helps many programmers begin to write recursive programs in a functional style, rather than an imperative style.

Note that in the first code snippet above, the if expression is choosing among two different solutions, depending on whether we see the symbol s in the first part of the pair or not. That's imperative thinking.

But look at the list-of-symbols data type:

    <list-of-symbols> ::= ()
                        | (<symbol> . <list-of-symbols>)

How many occurrences of s are in a pair? Obviously, the number of s's found in the car of the list plus the number of s's found in the cdr of the list. If we design our solution to match the code to the data type, then the addition operation should be at the top to begin:

    (+ ; number of s's found in the car
       ; number of s's found in the cdr )

If we define the answer for the problem in terms of the data type, we never create the duplication-by-if in the first place. We think about solving the subproblems for the car and the cdr, fill in the blanks, and arrive immediately at the refactored code snippet above.

I have been trying to help my students begin to "think functionally" sooner this semester. There is a lot or room for improvement yet in my approach. I'm glad this student asked his question so early in the semester, as it gave me another chance to model "follow the data" thinking. In any case, his thinking was on the right track.


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

December 27, 2012 12:08 PM

Agile Moments: Predicting What Users Want

the icon for VoodooPad

In this MacStories interview, Gus Mueller talks about the response to his latest release of VoodooPad.

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.

People really seem to like the Markdown syntax support and the new JavaScript events system I've built in for customization. I also added ePub export to VP5 which I expected more interest in -- but that hasn't seem to materialized. I'm never very good at predicting which features people will like the most.

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.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

December 14, 2012 3:50 PM

A Short Introduction to the Law of Demeter

Preface

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
  thisCollection.thisInsideCollection.thisAttribute.thisMethod()

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.

Or:

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:

  thisCollection.thisInsideCollection.thisAttribute.thisMethod()

The simplest way to eliminate the sender's need to know about thisInsideCollection and thisAttribute is to

  • add a method to thisCollection's class that accomplishes thisInsideCollection.thisAttribute.thisMethod(), and
  • send the new message to thisCollection:
      thisCollection.doSomething()
    

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:

  • Your code reflects the problem domain more faithfully.
  • Your code is easier to modify. You can now change the data structure used to implement the domain object without affecting the rest of the program.
  • Now you can solve the Law of Demeter violation by adding a method to the new class.

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.


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

December 10, 2012 2:54 PM

Brief Flashes of Understanding, Fully Awake

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.)


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

December 07, 2012 11:17 AM

Agglutination and Crystallization

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.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

November 26, 2012 3:24 PM

Quotes of the Day: Constraints on Programming

Obligation as constraint

Edward Yang has discovered the Three Bears pattern. He calls it "extremist programming".

When learning a new principle, try to apply it everywhere. That way, you'll learn more quickly where it does and doesn't work well, even if your initial intuitions about it are wrong.

Actually, you don't learn in spite of your initial intuitions being wrong. You learn because your initial intuitions were wrong. That's when learning happens best.

(I mention Three Bears every so often, such as Bright Lines in Learning and Doing, and whenever I discuss limiting usage of language features or primitive data values.)

Blindness as constraint

In an interview I linked to in my previous entry, Brian Eno and Ha-Joon Chang talk about the illusion of freedom. Whenever you talk about freedom, as in a "free market" or "free jazz",

... what you really mean is "constrained by rules that we've stopped thinking about".

Free jazz isn't entirely free, because you are constrained by what your muscles can do. Free markets aren't entirely free, because there are limits we simply choose not to talk about. Perhaps we once did talk about them and have chosen not to any more. Perhaps we never talked about them and don't even recognize that they are present.

I can't help but think of computer science faculty who claim we shouldn't be teaching OO programming in the first course, or any other "paradigm"; we should just teach basic programming first. They may be right about not teaching OOP first, but not because their approach is paradigm-free. It isn't.

(I mention constraints as a source of freedom every so often, including the ways in which patterns free students to create and the way creativity needs to be developed.)


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

November 18, 2012 9:13 AM

Programming Languages Quote of the Day

... comes from Gilad Bracha:

I firmly believe that a time traveling debugger is worth more than a boatload of language features[.]

This passage comes as part of a discussion of what it would take to make Bret Victor's vision of programming a reality. Victor demonstrates powerful ideas using "hand crafted illustrations of how such a tool might behave". Bracha, whose work on Smalltalk and Newspeak have long inspired me -- reflects on what it would take to offer Victor's powerful ideas in a general purpose programming environment.

Smalltalk as a language and environment works at a level where we conceive of providing the support Victor and Bracha envision, but most of the language tools people use today are too far removed from the dynamic behavior of the programs being written. The debugger is the most notable example.

Bracha suggests that we free the debugger from the constraints of time and make it a tool for guiding the evolution of the program. He acknowledges that he is not the first person to propose such an idea, pointing specifically to Bill Lewis's proposal for an omniscient debugger. What remains is the hard work needed to take the idea farther and provide programmers more transparent support for understanding dynamic behavior while still writing the code.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

November 17, 2012 12:23 PM

Why a CS Major Might Minor in Anthropology

Paul Klipp wrote a nice piece recently on emic and etic approaches to explaining team behavior. He explains what emic and etic approaches are and then shows how they apply to the consultant's job. For example:

Let's look at an example closer to home for us software folks. You're an agile coach, arriving in a new environment with a mission from management to "make this team more agile". If you, like so many consultants in most every field, favor an etic approach, you will begin by doing a gap analysis between the behaviors and artifacts that you see and those with which you are most familiar. That's useful, and practically inevitable. The next natural step, however, may be less helpful. That is to judge the gaps between what this team is doing and what you consider to be normal as wrong.... By deciding, as a consultant or coach, to now attempt to prepare an emic description of the team's behaviors, you force yourself to set aside your preconceptions and engage in meaningful conversations with the team in order to understand how they see themselves. Now you have two tools in your kit, where you might before have had one, and more tools prepares you for more situations.

When I speak to HS students and their parents, and when I advise freshmen, I suggest that the consider picking up a minor or a second major. I tell them that it almost doesn't matter which other discipline they choose. College is a good time to broaden oneself, to enjoy learning for its own sake. Some minors and second majors may seem more directly relevant to a CS grad's career interests, but you never know what domain or company you will end up working in. You never know when having studied a seemingly unrelated discipline will turn out to be useful.

Many students are surprised when I recommend social sciences such as psychology, sociology, and anthropology as great partners for CS. Their parents are, too. Understanding people, both individually and in groups, is important in any profession, but it is perhaps more important for CS grads than many. We build software -- for people. We teach new languages and techniques -- to people. We contract out our services to organizations -- of people. We introduce new practices and methodologies to organizations -- of people. Ethnography may be a more important to a software consultant's success than any set of business classes.

I had my first experience with this when I was a graduate student working in the area of knowledge-based systems. We built systems that aimed to capture the knowledge of human experts, often teams of experts. We found that they relied a lot on tacit knowledge, both in their individual expertise and in the fabric of their teams. It wasn't until I read some papers from John McDermott's research group at Carnegie Mellon that I realized we were all engaged in ethnographic studies. It would have been so useful to have had some background in anthropology!


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

November 16, 2012 2:50 PM

Preferring Objects over Class Methods in OOP

Bryan Helmkamp recently posted Why Ruby Class Methods Resist Refactoring on the Code Climate blog. It explains nicely example how using class methods makes it harder to refactor in a way that makes you feel like you have actually improved the code.

This is a hard lesson for beginners to learn, but even experienced Ruby and Java programmers sometimes succumb to the urge for simplicity that "just" writing a method offers. It doesn't take long for a simple class method to grow into something more complex, which gets in the way of growing the program.

As Helmkamp points out, class methods have the insidious feature of coupling your code to a particular class. Even when we program with instances rather than classes, we like to avoid that sort of coupling. Thus was born the factory method.

Deep in the process of teaching OO to undergraduates, I was drawn to an important truth found deep in the post, just after mention of the class-name coupling:

You can't easily swap in new a class, but you can easily swap in a new instance.

One of the great advantages of OOP is being able to plug a different object into a program and thus change or extend the program's behavior without modifying its code. Dynamic polymorphism via substitutable objects is in many ways the first principle of object-oriented programming.

That's why the first refactoring I usually apply whenever I encounter a class method is Introduce Object.


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

November 06, 2012 3:34 PM

A Good Name Is About An Idea, Not An Implementation

In The Poetry of Function Naming, Stephen Wolfram captures something that all programmers eventually learn:

[Naming functions is] an unforgiving and humbling activity. And the issue is almost always the same. The reason you can't find a good name is because you don't really understand with complete and ultimate clarity what the function does.

Sometimes we can't come up with the perfect name for a function or a variable until after we have written code that uses it. The act of writing the program helps us to learn about the program's content.

Later in the same blog entry, Wolfram says something that made me think of my previous blog, on how some questions presuppose how they are to be answered:

But in a computer language, each function name ultimately refers to a particular piece of functionality that is defined in an absolute way, and can be implemented by a specific precise program.

When we write OO programs, a name doesn't always refer to a specific function. With polymorphic variables, we don't usually know which method will be executed when we use a name. Any object that provides the protocol required by the variable's type, or implements the interface so named, may be stored in the variable. It may even be an instance of a class I know nothing about.

For this reason, when I teach OO programming, I am careful to talk about sending a message rather than "invoking a method" or "calling a function". The receiver of the message interprets the message, not the sender.

This doesn't invalidate what Wolfram says, though it does point to a way in which we might rephrase it more generally. The name of a good method isn't about specific functionality so much as about expectation. It's about the core idea associated with an interaction, not any particular implementation of that idea.


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

November 03, 2012 11:17 AM

When "What" Questions Presuppose "How"

John Cook wrote about times in mathematics when maybe you don't need to do what you were asked to do. As one example, he used remainder from division. In many cases, you don't need to do division, because you can find the answer using a different, often simpler, method.

We see a variation of John's theme in programming, too. Sometimes, a client will ask for a result in a way that presupposes the method that will be used to produce it. For example, "Use a stack to evaluate these nested expressions." We professors do this to students a lot, because they want the students to learn the particular technique specified. But you see subtle versions of this kind of request more often than you might expect outside the classroom.

An important part of learning to design software is learning to tease apart the subtle conflation of interface and implementation in the code we write. Students who learn OO programming after a traditional data structures course usually "get" the idea of data abstraction, yet still approach large problems in ways that let implementations leak out of their abstractions in the form of method names and return values. Kent Beck talked about how this problem afflicts even experienced programmers in his blog entry Naming From the Outside In.

Primitive Obsession is another symptom of conflating what we need with how we produce it. For beginners, it's natural to use base types to implement almost any behavior. Hey, the extreme programming principle You Ain't Gonna Need It encourages even us more experienced developers not to create abstractions too soon, until we know we need them and in what form. The convenience offered by hashes, featured so prominently in the scripting languages that many of us use these days, makes it easy to program for a long time without having to code a collection of any sort.

But learning to model domain objects as objects -- interfaces that do not presuppose implementation -- is one of the powerful stepping stones on the way to writing supple code, extendible and adaptable in the face of reasonable changes in the spec.


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

October 30, 2012 4:22 PM

Mathematical Formulas, The Great Gatsby, and Small Programs

... or: Why Less Code is Better

In Don't Kill Math, Evan Miller defends analytic methods in the sciences against Bret Victor's "visions for computer-assisted creativity and scientific understanding". (You can see some of my reactions to Victor's vision in a piece I wrote about his StrangeLoop talk.)

Miller writes:

For the practicing scientist, the chief virtue of analytic methods can be summed up in a single word: clarity. An equation describing a quantity of interest conveys what is important in determining that quantity and what is not at all important.

He goes on to look at examples such as the universal law of gravitation and shows that a single formula gives even a person with "minimal education in physics" an economical distillation of what matters. The clarity provided by a good analytic solution affords the reader two more crucial benefits: confident understanding and memorable insights.

Poet Peter Turchi describes a related phenomenon in fiction writing, in his essay You and I Know, Order is Everything. A story can pull us forward by omitting details and thus creating in the reader a desire to learn more. Referring to a particularly strategic paragraph, he writes:

That first sentence created a desire to know certain information: What is this significant event? ... We still don't have an answer, but the context for the question is becoming increasingly clear -- so while we're eager to have those initial questions answered, we're content to wait a little longer, because we're getting what seems to be important information. By the third paragraph, ... we think we've got a clue; but by that time the focus of the narrative is no longer the simple fact of what's going on, but the [larger setting of the story]. The story has shifted our attention from a minor mystery to a more significant one. On some level or another nearly every successful story works this way, leading us from one mystery to another, like stepping stones across a river.

In a good story, eventually...

... we recognize that the narrator was telling us more than we could understand, withholding information but also drawing our attention to the very thing we should be looking at.

In two very different contexts, we see the same forces at play. The quality of a description follows from the balance it strikes between what is in the description and what is left out.

To me, this is another example of how a liberal education can benefit students majoring in both the sciences and the humanities [ 1 | 2 ]. We can learn about many common themes and patterns of life from both traditions. Neither is primary. A student can encounter the idea first in the sciences, or first in the humanities, whichever interests the student more. But apprehending a beautiful pattern in multiple domains of discourse can reinforce the idea and make it more salient in the preferred domain. This also broadens our imaginations, allowing us to see more patterns and more subtlety in the patterns we already know.

So: a good description, a good story, depends in some part on the clarity attendant in how it conveys what is important and what is not important. What are the implications of this pattern for programming? A computer program is, after all a description: an executable description of a domain or phenomenon.

I think this pattern gives us insight into why less code is usually better than more code. Given two functionally equivalent programs of different lengths, we generally prefer the shorter program because it contains only what matters. The excess code found in the longer program obscures from the reader what is essential. Furthermore, as with Miller's concise formulas, a short program offers its reader the gift of more confident understanding and the opportunity for memorable insights.

What is not in a program can tell us a lot, too. One of the hallmarks of expert programmers is their ability to see the negative space in a design and program and learn from it. My students, who are generally novice programmers, struggle with this. They are still learning what matters and how to write descriptions at all, let alone concise one. They are still learning how to focus their programming tools, and on what.


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

October 16, 2012 4:45 PM

The Parable of the OO Programming Student

As The Master was setting out on a journey, a young man ran up, knelt down before him, and asked him, "Good teacher, what must I do to inherit the eternal bliss of OO?"

The Master answered him, "Why do you call me good? No OO programmer is good but The Creator alone.

"You know the commandments: "'An object should have only a single responsibility.'

"'Software entities should be open for extension, but closed for modification.'

"'Objects should be replaceable with instances of their subtypes without altering the correctness of that program.'

"'Tell, don't ask.'

"'You shall not indulge in primitive obsession.'

"'All state is private.'"

The young man replied and said to Him, "Teacher, all of these I have observed from my youth when first I learned to program."

The Master, looking at him, loved him and said to him, "You are lacking in one thing. Go, surrender all primitive types, and renounce all control structures. Write all code as messages passed between encapsulated objects, with extreme late-binding of all things. Then will you have treasure in Heaven; then come, follow me."

At that statement the young man's face fell, and he went away sad, for he possessed many data structures and algorithms.

The Master looked around and said to his disciples, "How hard it is for those who have a wealth of procedural programming experience to enter the kingdom of OO."

... with apologies to The Gospel of Mark.


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

October 02, 2012 4:14 PM

The Pareto Principle and Programming Purity

After talking about the advantages of making the changeable aspects of the system as declarative as possible, William Payne writes:

Having done a bit of Prolog programming in the dim and distant past, my intuition is that trying to make everything declarative is a mistake; one ends up tying oneself into knots. The mental gymnastics simply are not worth it. However, splitting the program into declarative-and-non-declarative parts seems reasonable.

This is an application of the Pareto Principle to programming, in the form of the purity of style. The Pareto Principle says that, "for many events, roughly 80% of the effects come from 20% of the causes".

When I was first learning functional programming in Lisp as an AI researcher, a more experienced researcher told me that about 90% of a big system could be purely functional. The remaining 10% should include all side-effecting operations, cordoned off from the rest of the app into its own abstraction layer. Since that time, I've heard 85-15 used as a reasonable split for big Scheme programs.

The lesson is: don't kill yourself trying to be 100%. As Payne says, the mental gymnastics simply are not worth it. You'll end up with code that easier to understand, maintain, and modify if you allow yourself a little impurity, in small, controlled doses.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

September 30, 2012 12:45 PM

StrangeLoop 8: Reactions to Brett Victor's Visible Programming

The last talk I attended at StrangeLoop 2012 was Bret Victor's Visible Programming. He has since posted an extended version of his presentation, as a multimedia essay titled Learnable Programming. You really should read his essay and play the video in which he demonstrates the implementation of his ideas. It is quite impressive, and worthy of the discussion his ideas have engendered over the last few months.

In this entry, I give only a high-level summary of the idea, react to only one of his claims, and discuss only one of his design principles in ay detail. This entry grew much longer than I originally intended. If you would like to skip most of my reaction, jump to the mini-essay that is the heart of this entry, Programing By Reacting, in the REPL.

~~~~

Programmers often discuss their productivity as at least a partial result of the programming environments they use. Victor thinks this is dangerously wrong. It implies, he says, that the difficulty with programming is that we aren't doing it fast enough.

But speed is not the problem. The problem is that our programming environments don't help us to think. We do all of our programming in our minds, then we dump our ideas into code via the editor.

Our environments should do more. They should be our external imagination. They should help us see how our programs work as we are writing them.

This is an attractive guiding principle for designing tools to help programmers. Victor elaborates this principle into a set of five design principles for an environment:

  • read the vocabulary -- what do these words mean?
  • follow the flow -- what happens when?
  • see the state -- what is the computer thinking?
  • create by reacting -- start somewhere, then sculpt
  • create by abstracting -- start concrete, then generalize

Victor's talk then discussed each design principle in detail and showed how one might implement the idea using JavaScript and Processing.js in a web browser. The demo was cool enough that the StrangeLoop crowd broke into applause at leas twice during the talk. Read the essay.

~~~~

As I watched the talk, I found myself reacting in a way I had not expected. So many people have spoken so highly of this work. The crowd was applauding! Why was I not as enamored? I was impressed, for sure, and I was thinking about ways to use these ideas to improve my teaching. But I wasn't falling head over heels in love.

A Strong Claim

First, I was taken aback by a particular claim that Victor made at the beginning of his talk as one of the justifications for this work:

If a programmer cannot see what a program is doing, she can't understand it.

Unless he means this metaphorically, seeing "in the mind's eye", then it is simply wrong. We do understand things we don't see in physical form. We learn many things without seeing them in physical form. During my doctoral study, I took several courses in philosophy, and only rarely did we have recourse to images of the ideas we were studying. We held ideas in our head, expressed in words, and manipulated them there.

We did externalize ideas, both as a way to learn them and think about them. But we tended to use stories, not pictures. By speaking an idea, or writing it down, and sharing it with others, we could work with them.

So, my discomfort with one of Victor's axioms accounted for some of my unexpected reaction. Professional programmers can and do manipulate ideas abstractly. Visualization can help, but when is it necessary, or even most helpful?

Learning, Versus Doing

This leads to a second element of my concern. I think I had a misconception about Victor's work. His talk and its title, "Visible Programming", led me to think his ideas are aimed primarily at working programmers, that we need to make programs visible for all programmers.

The title of his essay, "Learnable Programming", puts his claims into a different context. We need to make programs visible for people who are learning to program. This seems a much more reasonable position on its face. It also lets me see the axiom that bothered me so much in a more sympathetic light: If a novice programmer cannot see what a program is doing, then she may not be able to understand it.

Seeing how a program works is a big part of learning to program. A few years ago, I wrote about "biction" and the power of drawing a picture of what code does. I often find that if I require a student to draw a picture of what his code is doing before he can ask me for debugging help, he will answer his own question before getting to me.

The first time a student experiences this can be a powerful experience. Many students begin to think of programming in a different way when they realize the power of thinking about their programs using tools other than code. Visible programming environments can play a role in helping students think about their programs, outside their code and outside their heads.

I am left puzzling over two thoughts:

  • How much of the value my students see in pictures comes from not from seeing the program work but from drawing the picture themselves -- the act of reflecting about the program? If our tools visualizes the code for them, will we see the same learning effect that we see in drawing their own pictures?

  • Certainly Victor's visible programming tools can help learners. How much will they help programmers once they become experts? Ben Shneiderman's Designing the User Interface taught me that novices and experts have different needs, and that it's often difficult to know what works well for experts until we run experiments.

Mark Guzdial has written a more detailed analysis of Victor's essay from the perspective of a computer science educator. As always, Mark's ideas are worth reading.

Programming By Reacting, in the REPL

My favorite parts of this talk were the sections on creating by reacting and abstracting. Programmers, Victor says, don't work like other creators. Painters don't stare at a blank canvas, think hard, create a painting in their minds, and then start painting the picture they know they want to create. Sculptors don't stare at a block of stone, envision in their mind's eye the statue they intend to make, and then reproduce that vision in stone. They start creating, and react, both to the work of art they are creating and to the materials they are using.

Programmers, Victor says, should be able to do the same thing -- if only our programming environments helped us.

As a teacher, I think this is an area ripe for improvement in how we help students learn to program. Students open up their text editor or IDE, stare at that blank screen, and are terrified. What do I do now? A lot of my work over the last fifteen to twenty years has been in trying to find ways to help students get started, to help them to overcome the fear of the blank screen.

My approaches haven't been through visualization, but through other ways to think about programs and how we grow them. Elementary patterns can give students tools for thinking about problems and growing their code at a scale larger than characters or language keywords. An agile approach can help them start small, add one feature at a time, proceed in confidence with working tests, and refactor to make their code better as they go along. Adding Victor-style environment support for the code students write in CS1 and CS2 would surely help as well.

However, as I listened to Victor describe support for creating by reacting, and then abstracting variables and functions out of concrete examples, I realized something. Programmers don't typically write code in an environment with data visualizations of the sort Victor proposes, but we do program in the style that such visualizations enable.

We do it in the REPL!

A simple, interactive computer programming environment enables programmers to create by reacting.

  • They write short snippets of code that describe how a new feature will work.
  • They test the code immediately, seeing concrete results from concrete examples.
  • They react to the results, shaping their code in response to what the code and its output tell them.
  • They then abstract working behaviors into functions that can be used to implement another level of functionality.

Programmers from the Lisp and Smalltalk communities, and from the rest of the dynamic programming world, will recognize this style of programming. It's what we do, a form of creating by reacting, from concrete examples in the interaction pane to code in the definitions pane.

In the agile software development world, test-first development encourages a similar style of programming, from concrete examples in the test case to minimal code in the application class. Test-driven design stimulates an even more consciously reactive style of programming, in which the programmer reacts both to the evolving program and to the programmer's evolving understanding of it.

The result is something similar to Victor's goal for programmers as they create abstractions:

The learner always gets the experience of interactively controlling the lower-level details, understanding them, developing trust in them, before handing off that control to an abstraction and moving to a higher level of control.

It seems that Victor would like to perform even more support for novices than these tools can provide, down to visualizing what the program does as they type each line of code. IDEs with autocomplete is perhaps the closest analog in our current arsenal. Perhaps we can do more, not only for novices but also professionals.

~~~~

I love the idea that our environments could do more for us, to be our external imaginations.

Like many programmers, though, as I watched this talk, I occasionally wondered, "Sure, this works great if you creating art in Processing. What about when I'm writing a compiler? What should my editor do then?"

Victor anticipated this question and pre-emptively answered it. Rather than asking, How does this scale to what I do?, we should turn the question inside out and ask, These are the design requirements for a good environment. How do we change programming to fit?

I doubt such a dogmatic turn will convince skeptics with serious doubts about this approach.

I do think, though, that we can reformulate the original question in a way that focuses on helping "real" programmers. What does a non-graphical programmer need in an external imagination? What kind of feedback -- frequent, even in-the-moment -- would be most helpful to, say, a compiler writer? How could our REPLs provide even more support for creating, reacting, and abstracting?

These questions are worth asking, whatever one thinks of Victor's particular proposal. Programmers should be grateful for his causing us to ask them.


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

September 29, 2012 4:04 PM

StrangeLoop 7: The Racket Way

I have been using Racket since before it was Racket, back when it was "just another implementation of Scheme". Even then, though, it wasn't just another implementation of Scheme, because it had such great libraries, a devoted educational community around it, and an increasingly powerful facility for creating and packaging languages. I've never been a deep user of Racket, though, so I was eager to see this talk by one of its creators and learn from him.

Depending on your perspective, Racket is either a programming language (that looks a lot like Scheme), a language plus a set of libraries, or a platform for creating programs. This talk set out to show us that Racket is more.

Flatt opened with a cute animated fairy tale, about three princesses who come upon a wishing well. The first asks for stuff. The second asks for more wishes. The third asks for a kingdom full of wishing wells. Smart girl, that third one. Why settle for stuff when you can have the source of all stuff?

This is, Flatt said, something like computer science. There is a similar progression of power from:

  • a document, to
  • a language for documents, to
  • a language for languages.

Computer scientists wish for a way to write programs that do... whatever.

This is the Racket way:

  1. Everything is a program.
  2. Concepts are programming language constructs.
  3. Programming languages are extensible and composable.

The rest of the talk was a series of impressive mini-demos that illustrated each part of the Racket way.

To show what it means to say that everything is a program, Flatt demoed Scribble, a language for producing documents -- even the one he was using to give his talk. Scribble allows writers to abstract over every action.

To show what it means to say that concepts are programming language constructs, Flatt talked about the implementation of Dr. Racket, the flexible IDE that comes with the system. Dr. Racket needs to be able to create, control, and terminate processes. Relying on the OS to do this for it means deferring to what that OS offers. In the end, that means no control.

Dr. Racket needs to control everything, so the language provides constructs for these concepts. Flatt showed as examples threads and custodians. He then showed this idea at work in an incisive way: he wrote a mini-Dr. Racket, called Racket, Esq. -- live using Racket. To illustrate its completeness, he then ran his talk inside racket-esq. Talk about a strange loop. Very nice.

To show what it means to say that programming languages are extensible and composable, Flatt showed a graph of the full panoply of Racket's built-in languages and demoed several languages. He then used some of the basic language-building tools in Racket -- #lang, require, define-syntax, syntax-rules, and define-syntax-rule -- to build the old text-based game Adventure, which needs a natural language-like scripting language for defining worlds. Again, very nice -- so much power in so many tools.

This kind of power comes from taking seriously a particular way of thinking about the world. It starts with "Everything is a program." That is the Racket way.

Flatt is a relaxed and confident presenter. As a result, this was a deceptively impressive talk. It reinforced its own message by the medium in which it was delivered: using documents -- programs -- written and processed in Racket. I am not sure how anyone could see a slideshow with "hot" code, a console for output, and a REPL within reach, all written in the environment being demoed, and not be moved to rethink how they write programs. And everything else they create.

As Flatt intimated briefly early on, The Racket Way of thinking is not -- or should not be -- limited to Racket. It is, at its core, the essence of of computer science. The duality of code and data makes what we do so much more powerful than most people realize, and makes what we can do so much more powerful than most us actually do with the tools we accept. I hope that Flatt's talk inspires a few more of us not to settle for less than we have to.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

September 29, 2012 3:40 PM

StrangeLoop 6: Y Y

I don't know if it was coincidence or by design of the conference organizers, but Wednesday morning was a topical repeat of Tuesday morning for me: two highly engaging talks on functional programming. I had originally intended to write them up in a single entry, but that write-up grew so long that I decided to give them their own entries.

Y Not?

Watching talks and reading papers about the Y combinator are something of a spectator code kata for me. I love to see new treatments, and enjoy seeing even standard treatments every now and then. Jim Weirich presented it at StrangeLoop with a twist I hadn't seen before.

Weirich opened, as speakers often do, with him. This is a motivational talk, so it should be...

  • non-technical. But it's not. It is highly technical.
  • relevant. But it's not. It is extremely pointless.
  • good code. But it's not. It shows the worst Clojure code ever.

But it will be, he promises, fun!

Before diving in, he had one more joke, or at least the first half of one. He asked for audience participation, then asked his volunteer to calculate cos(n) for some value of n I missed. Then he asked the person to keep hitting the cosine button repeatedly until he told him to stop.

At the dawn of computing, to different approaches were taken in an effort to answer the question, What is effectively computable?

Alan Turing devised what we now call a universal Turing machine to embody the idea. Weirich showed a video demonstration of a physical Turing machine to give his audience a sense of what a TM is like.

(If you'd like to read more about Turing and the implication of his universal machine, check out this reflection I wrote earlier this year after a visit by Doug Hofstadter to my campus. Let's just say that the universal TM means more than just an answer to what functions are effectively computable.)

A bit ahead of Turing, Alonzo Church devised an answer to the same question in the form of the lambda calculus, a formal logical system. As with the universal TM, the lambda calculus can be used to compute everything, for a particular value of eveything. These days, nearly every programming language has lambdas of some form

... now came the second half of the joke running in the background. Weirich asked his audience collaborator what was in his calculator's display. The assistant called out some number, 0.7... Then Weirich showed his next slide -- the same number, taken out many more digits. How was he able to do this? There is a number n such that cos(n) = n. By repeatedly pressing his cosine button, Weirich's assistant eventually reached it. That number n is called the fixed point of the cosine function. Other functions have fixed points to, and they can be a source of great fun.

Then Weirich opened up his letter and wrote some code from the ground up to teach some important concepts of functional programming, using the innocuous function 3(n+1). With this short demo, Weirich demonstrated the idea of a higher-order function, including function factories, a set of useful functional refactorings that included

  • Introduce Binding
    -- where the new binding is unused in the body
  • Inline Definition
    -- where a call to a function is replaced by the function body, suitably parameterized
  • Wrap Function
    -- where an expression is replaced by a function call that computes the expression
  • Tennent Correspondence Principle
    -- where an expression is turned into a think

At the end of his exercise, Weirich had created a big function call that contained no named function definitions yet computed the same answer.

He asks the crowd for applause, then demurs. This is 80-year-old technology. Now you know, he says, what a "chief scientist" at New Context does. (Looks a lot like what an academic might do...)

Weirich began a second coding exercise, the point behind all his exposition to this point: He wrote the factorial function, and began to factor and refactor it just as he had the simpler 3(n+1). But now inlining the function breaks the code! There is a recursive call, and the name is now out of scope. What to do?

He refactors, and refactors some more, until the body of factorial is an argument to a big melange of lambdas and applications of lambdas. The result is a function that computes the fixed point of any function passed it.

That is Y. The Y combinator.

Weirich talked a bit about Y and related ideas, and why it matters. He closed with a quote from Wittgenstein, from Philosophical Investigations:

The aspects of things that are most important for us are hidden because of their simplicity and familiarity. (One is unable to notice something -- because it is always before one's eyes.) The real foundations of his enquiry do not strike a man at all. Unless that fact has at some time struck him. -- And this means: we fail to be struck by what, once seen, is most striking and most powerful.

The thing that sets Weirich's presentation of Y apart from the many others I've seen is its explicit use of refactoring to derive Y. He created Y from a sequence of working pieces of code, each the result of a refactoring we can all understand. I love to do this sort of thing when teaching programming ideas, and I was pleased to see it used to such good effect on such a challenging idea.

The title of this talk -- Y Not? -- plays on Y's interrogative homonym. Another classic in this genre echos the homonym in its title, then goes on to explain Y in four pages of English and Scheme. I suggest that you study @rpg's essay while waiting for Weirich's talk to hit InfoQ. Then watch Weirich's talk. You'll like it.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Patterns, Software Development

September 28, 2012 3:59 PM

StrangeLoop 5: Miscellany -- At All Levels

Most of the Tuesday afternoon talks engaged me less deeply than the ones that came before. Part of that was the content, part was the style of delivery, and part was surely that my brain was swimming in so many percolating ideas that there wasn't room for much more.

Lazy Guesses

Oleg Kiselyov, a co-author of the work behind yesterday's talk on miniKanren, gave a talk on how to implement guessing in computer code. That may sound silly, for a couple of reasons. But it's not.

First, why would we want to guess at all? Don't we want to follow principles that guarantee we find the right answer? Certainly, but those principles aren't always available, and even when they are the algorithms that implement them may be computationally intractable. So we choose to implement solutions that restrict the search space, for which we pay a price along some other dimension, often expressiveness.

Kiselyov mentioned scheduling tasks early in his talk, and any student of AI can list many other problems for which "generate and test" is a surprisingly viable strategy. Later in the talk, he mentioned parsing, which is also a useful example. Most interesting grammars have nondeterministic choices in them. Rather than allow our parsers to make choices and fail, we usually adopt rules that make the process predictable. The result is an efficient parser, but a loss in what we can reasonably say in the language.

So, perhaps the ability to make good guesses is valuable. What is so hard about implementing them? The real problem is that there are so many bad guesses. We'd like to use knowledge to guide the process of guessing again, to favor some guesses over others.

The abstract for the talk promises a general principle on which to build guessing systems. I must admit that I did not see it. Kiselyov moved fast at times through his code, and I lost sight of the big picture. I did see discussions of forking a process at the OS level, a fair amount of OCaml code, parser combinators, and lazy evaluation. Perhaps my attention drifted elsewhere at a key moment.

The speaker closed his talk by showing a dense slide and saying, "Here is a list of buzzwords, some of which I said in my talk and some of which I didn't say in my talk." That made me laugh: a summary of a talk he may or may not have given. That seemed like a great way to end a talk about guessing.

Akka

I don't know much about the details of Akka. Many of my Scala-hacking former students talk about it every so often, so I figured I'd listen to this quick tour and pick up a little more. The underlying idea, of course, is Hewitt's Actor model. This is something I'm familiar with from my days in AI and my interest in Smalltalk.

The presenter, Akka creator Jonas Boner, reminded the audience that Actors were a strong influence on the original Smalltalk. In many ways, it is truer to Kay's vision of OOP than the languages we use today.

This talk was a decent introduction to Hewitt's idea and its implementation in Akka. My two favorite things from the talk weren't technical details, but word play:

  • The name "Akka" has many inspirations, including a mountain in northern Sweden, a goddess of the indigenous people of northern Scandinavia, and a palindrome of Actor Kernel / Kernel Actor.

  • Out of context, this quote made the talk for me:
    We have made some optimizations to random.
    Ah, aren't we all looking for those?

Expressiveness and Abstraction

This talk by Ola Bini was a personal meditation on the expressiveness of language. Bini, whose first slide listed him as a "computational metalinguist", started from the idea that, informally, the expressiveness of a language is inversely proportional to the distance between our thoughts and the code we have to write in that language.

In the middle part of the talk, he considered a number of aspects of expressiveness and abstraction. In the latter part, he listed ideas from natural language and wondered aloud what their equivalents would be in programming languages, among them similes, metaphors, repetition, elaboration, and multiple equivalent expressions with different connotations.

During this part of the talk, my mind wandered, too, to a blog entry I wrote about parts of speech in programming languages back in 2003, and a talk by Crista Lopes at OOPSLA that year. Nouns, verbs, pronouns, adjectives, and adverbs -- these are terms I use metaphorically when teaching students about new languages. Then I thought about different kinds of sentence -- declarative, interrogative, imperative, and exclamatory -- and began to think about their metaphorical appearances in our programming languages.

Another fitting way for a talk to end: my mind wondering at the end of a wondering talk.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

September 26, 2012 8:12 PM

StrangeLoop 3: Functional Programming 1 -- Monads and Patterns

The StrangeLoop program had a fair amount of functional programming talks, and I availed myself of two to complete the first morning of the conference.

Monad Examples for Normal People

The web is full of tutorials claiming to explain monads in a way that anyone can understand. If any of them had succeeded, we wouldn't need another. How could I not attend a talk claiming to slay this dragon?

Getz started out with a traditional starting point: a sequence of operations that can be viewed as composition of functions. That works great for standard business logic. But consider a common exceptional case: given a name, looking up an account number fails. This requires us to break the symmetry of the code with guards. These break composition, because now the return type of the function doesn't fit.

The Maybe monad factors these guards out of the business logic. If we further need to record and capture error coded, we can use the Error monad, which factors the same sort of plumbing out of the business logic and also serves as a facade for a tuple of value and error code.

After these simple examples, the speaker dove into the sort of exercise that tends to lose the interest of programmers in the trenches building apps: building a Lisp interpreter in Python, using monads to compose the elements of the interpreter. The environment consists of a combination of the reader monad and the writer monad; the interpreter consists of a combination of the environment and the error monad. Several other monads play a role in representing values, built-in procedures, state, and non-standard control operators. An interpreter is, he said, "monad heaven".

The best part of this talks message was in viewing a monad as a design pattern that abstracts repetitive plumbing out of applications in such a way that preserves function composition.

After the talk, someone asked a question to the effect, "I get by fine with macros and higher-order functions. When do I need monads?" Getz answered from his personal experience: monads enable him to write more elegant code, by factoring repetition that other tools could not reach as nicely.

This wasn't the monad explanation to end the need for new monad explanations, but it was a decent effort. With the Getz's focus on factoring code and the question mentioning macros, I could not help but think of this essay that presents monads in the light of code transformation, and Brian Marick's approach treating a monad as a macro. Perhaps we are getting near a metaphor for monads that will help "normal people" grok them without resorting to abstract abstract math.

Functional Design Patterns

From the moment I saw the StrangeLoop line-up, I was excited to see Stuart Sierra speak on functional design patterns. Sierra is one of the few prominent people in the Lisp and Clojure worlds to acknowledge the value of design patterns in functional style -- heck, even to acknowledge they exist.

He opened his talk in a way that confronted the view commonly held among Lispers, He conceded that, for many, "design pattern" is a loaded term, bringing to mind an OO cult and the ominous voice of the Gang of Four. The thing is, Sierra said, Design Patterns is a pretty good book, given the time it was written and the programming language community to which it. speaks. However, in the functional language community, the design patterns in that book are best known for being debunked by Peter Norvig in a 1998 tutorial.

Sierra reminded this audience that patterns can occur at all levels of a program. He pointed to a lower-profile patterns book of the mid-1990s, Pattern-Oriented Software Architecture (now a five-volume series), which organized patterns at multiple levels:

  • architectural -- across components
  • design -- within components
  • idiom -- within a particular language

Sierra then went on to list, and describe briefly, several common patterns he has noticed in functional programs and used himself in Clojure. Like POSA, he organized them into categories. Before proceeding, he admitted to any Haskell programmers in the room that, yes, many of these patterns are monadic in nature.

I'd very much like to write about some of Sierra's patterns in greater detail than a single entry permits, including providing links to blog entries he and others have written about them. For now, let me list the ones I jotted down, in Sierra's categories:

  • state patterns
    • State/Event, aka Event Sourcing
    • Consequences

  • data-building patterns
    • Accumulator
    • Reduce/Combine
    • Recursive Expansion

  • control flow patterns
    • Pipeline
    • Wrapper
    • Token
    • Observer
    • Strategy

Before describing Reduce/Combine, Sierra took a short digression to talk about MapReduce, a pattern accepted by many in the world of big data. He reminded us that this pattern is predicated on the spinning disk becoming the bottleneck of our system. In the future, this pattern will become less useful as other forces come to dominate our system architecture.

Two of the control flow patterns, Observer and Strategy, are held in common with the GoF catalog, though in the context of functional programming a few new variations become more obvious. It also seemed to me that Sierra's Wrapper is a lot like the GoF's Decorator, though he did not make an explicit connection.

As I wrote a couple of years ago, the time is right for functional design patterns. I'm so glad that Sierra has been documented patterns of this sort and articulating the value of thinking in terms of patterns. The key is not to look to OO programs for patterns of value to functional programmers, but to look at functional programs for recurring choices among design alternatives. (It's not too surprising that many OO design patterns don't mean much to functional programmers, just as it's not surprising that FP patterns dealing with, say, state are afterthoughts in the OO world.)

I look forward to reviewing Sierra's slides, available at StrangeLoop 2012 GitHub repo, and coming back to the topic of functional design patterns soon.

The first day of StrangeLoop was off to a great start.


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

September 25, 2012 8:35 PM

StrangeLoop 1: A Miscellany of Ideas

For my lunch break, I walked a bit outside, to see the sun and bend my knee a bit. I came back for a set of talks without an obvious common thread. After seeing the talks, I saw a theme: ideas for writing programs more conveniently or more concisely.

ClojureScript

David Nolen talked about ClojureScript, a Clojure-like language that compiles to Javascript. As he noted, there is a lot of work in this space, both older and newer. The goal of all that work is to write Javascript more conveniently, or generate it from something else. The goal of ClojureScript is to bring the expressibility and flexible programming style of the Lisp world to JS world. Nolen's talk gave us some insights into the work being done to make the compiler produce efficient Javascript, as well as into why you might use ClojureScript in the first place.

Data Structures and Hidden Code

The message of this talk by Scott Vokes is that your choice in data structures plays a big role in determining how much code you have to write. You can make a lot of code disappear by using more powerful data structures. We can, of course, generalize this claim from data structures to data. This is the theme of functional and object-oriented programming, too. This talk highlights how often we forget the lowly data structure when we think of writing less code.

As Vokes said, your choice in data structures sets the "path of least resistance" for what your program will do and also for the code you will write. When you start writing code, you often don't know what the best data structure for your application is. As long as you don't paint yourself into a corner, you should be able to swap a new structure in for the old. The key to this is something novice programmers learn early, writing code not in terms of a data structure but in terms of higher-level behaviors. Primitive obsession can become implementation obsession if you aren't careful.

The meat of this talk was a quick review of four data structures that most programmers don't learn in school: skip lists, difference list, rolling hashes, and jumpropes, a structure Vokes claims to invented.

This talk was a source of several good quote, including

  • "A data structure is just a stupid programming language." -- Bill Gosper
  • "A data structure is just a virtual machine." -- Vokes himself, responding to Gosper
  • "The cheapest, fastest, and most reliable components are those that aren't there." -- Gordon Bell

The first two quotes there would make nice mottos for a debate between functional and OO programming. They also are two sides of the same coin, which destroys the premise of the debate.

miniKanren

As a Scheme programmer and a teacher of programming languages, I have developed great respect and fondness for the work of Dan Friedman over the last fifteen years. As a computer programmer who began his studies deeply interested in AI, I have long had a fondness for Prolog. How could I not go to the talk on miniKanren? This is a small implementation (~600 lines written in a subset of Scheme) of Kanren, a declarative logic programming system described in The Reasoned Schemer.

This talk was like a tag-team vaudeville act featuring Friedman and co-author William Byrd. I can't so this talk justice in a blog entry. Friedman and Byrd interleaved code demo with exposition as they

  • showed miniKanren at its simplest, built from three operators (fresh, conde, and run)
  • extended the language with a few convenient operators for specifying constraints, types, and exclusions, and
  • illustrated how to program in miniKanren by building a language interpreter, EOPL style.

The cool endpoint of using logic programming to build the interpreter is that, by using variables in a specification, the interpreter produces legal programs that meet a given specification. It generates code via constraint resolution.

If that weren't enough, they also demo'ed how their system can, given a language grammar, produce quines -- programs p such that

    (equal p (eval p))
-- and twines, pairs of programs p and q such that
    (and (equal p (eval q))
         (equal q (eval p)))

Then they live-coded an implementation of typed lambda calculus.

Yes, all in fifty minutes. Like I said, you really need to watch the talk at InfoQ as soon as it's posted.

In the course of giving the talk, Friedman stated a rule that my students can use:

Will's law: If your function has a recursion, do the recursion last.

Will followed up with cautionary advice:

Will's second law: If your function has two recursions, call Will.

We'll see how serious he was when I put a link to his e-mail address in my Programming Languages class notes next spring.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

September 25, 2012 7:31 PM

Blogging from StrangeLoop

StrangeLoop logo

This week I have the pleasure of spending a couple of days expanding my mind at StrangeLoop 2012. I like StrangeLoop because it's a conference for programmers. The program is filled with hot programming topics and languages, plus a few keynotes to punctuate our mental equilibria. The 2010 conference gave me plenty to think about, but I had to skip 2011 while teaching and recovering. This year was a must-see.

I'll be posting the following entries from the conference as time permits me to write them.

You can find links to other write-ups of the conference, as well as slides from some talks and other material, at the StrangeLoop 2012 github site.

Now that the conference has ended, I can say with confidence that StrangeLoop 2012 was even better than StrangeLoop 2010.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

September 20, 2012 8:09 PM

Computer Science is a Liberal Art

Over the summer, I gave a talk as part of a one-day conference on the STEM disciplines for area K-12, community college, and university advisors. They were interested in, among other things, the kind of classes that CS students take at the university and the kind of jobs they get when they graduate.

In the course of talking about how some of the courses our students take (say, algorithms and the theory of computing) seem rather disconnected from many of the jobs they get (say, web programmer and business analyst), I claimed that the more abstract courses prepare students to understand the parts of the computing world that never change, and the ones that do. The specific programming languages or development stack they use after they graduate to build financial reporting software may change occasionally, but the foundation they get as a CS major prepares them to understand what comes next and to adapt quickly.

In this respect, I said, a university CS education is not job training. Computer Science is a liberal art.

This is certainly true when you compare university CS education with what students get at a community college. Students who come out of a community college networking program often possess specific marketable skills at a level we are hard-pressed to meet in a university program. We bank our program's value on how well it prepares students for a career, in which networking infrastructure changes multiple times and our grads are asked to work at the intersection of networks and other areas of computing, some of which may not exist yet.

It is also true relative to the industries they enter after graduation. A CS education provides a set of basic skills and, more important, several ways to think about problems and formulate solutions. Again, students who come out of a targeted industry or 2-year college training program in, say, web dev, often have "shovel ready" skills that are valuable in industry and thus highly marketable. We bank our program's value on how well it prepares students for a career in which ASP turns to JSP turns PHP turns to JavaScript. Our students should be prepared to ramp up quickly and have a shovel in the hands producing value soon.

And, yes, students in a CS program must learn to write code. That's a basic skill. I often hear people comment that computer science programs do not prepare students well for careers in software development. I'm not sure that's true, at least at schools like mine. We can't get away with teaching all theory and abstraction; our students have to get jobs. We don't try to teach them everything they need to know to be good software developers, or even many particular somethings. That should and will come on the job. I want my students to be prepared for whatever they encounter. If their company decides to go deep with Scala, I'd like my former students to be ready to go with them.

In a comment on John Cook's timely blog entry How long will there be computer science departments?, Daniel Lemire suggests that we emulate the model of medical education, in which doctors serve several years in residency, working closely with experienced doctors and learning the profession deeply. I agree. Remember, though, that aspiring doctors go to school for many years before they start residency. In school, they study biology, chemistry, anatomy, and physiology -- the basic science at the foundation of their profession. That study prepares them to understand medicine at a much deeper level than they otherwise might. That's the role CS should play for software developers.

(Lemire also smartly points out that programmers have the ability to do residency almost any time they like, by joining an open source project. I love to read about how Dave Humphrey and people like him bring open-source apprenticeship directly into the undergrad CS experience and wonder how we might do something similar here.)

So, my claim that Computer Science is a liberal arts program for software developers may be crazy, but it's not entirely crazy. I am willing to go even further. I think it's reasonable to consider Computer Science as part of the liberal arts for everyone.

I'm certainly not the first person to say this. In 2010, Doug Baldwin and Alyce Brady wrote a guest editors' introduction to a special issue of the ACM Transactions on Computing Education called Computer Science in the Liberal Arts. In it, they say:

In late Roman and early medieval times, seven fields of study, rooted in classical Greek learning, became canonized as the "artes liberales" [Wagner 1983], a phrase denoting the knowledge and intellectual skills appropriate for citizens free from the need to labor at the behest of others. Such citizens had ample leisure time in which to pursue their own interests, but were also (ideally) civic, economic, or moral leaders of society.

...

[Today] people ... are increasingly thinking in terms of the processes by which things happen and the information that describes those processes and their results -- as a computer scientist would put it, in terms of algorithms and data. This transformation is evident in the explosion of activity in computational branches of the natural and social sciences, in recent attention to "business processes," in emerging interest in "digital humanities," etc. As the transformation proceeds, an adequate education for any aspect of life demands some acquaintance with such fundamental computer science concepts as algorithms, information, and the capabilities and limitations of both.

The real value in a traditional Liberal Arts education is in helping us find better ways to live, to expose us to the best thoughts of men and women in hopes that we choose a way to live, rather than have history or accident choose a way to live for us. Computer science, like mathematics, can play a valuable role in helping students connect with their best aspirations. In this sense, I am comfortable at least entertaining the idea that CS is one of the modern liberal arts.


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

September 19, 2012 4:57 PM

Don't Stop The Car

I'm not a Pomodoro guy, but this advice from The Timer Knows Best applies more generally:

Last month I was teaching my wife to drive [a manual transmission car], and it's amazing how easy stick shifting is if the car is already moving.... However, when the car is stopped and you need to get into 1st gear, it's extremely difficult. [So many things can go wrong:] too little gas, too much clutch, etc. ...

The same is true with the work day. Once you get going, you want to avoid coming to a standstill and having to get yourself moving again.

As I make the move from runner to cyclist, I have learned how much easier to keep moving on a bike than it is to start moving on a bike.

This is true of programming, too. Test-driven development helps us get started by encouraging us to focus on one new piece of functionality to implement. Keep it small, make it work, and move on to another small step. Pretty soon you are moving, and you are on your way.

Another technique many programs use to get started is to code a failing test before you stop the day before. This failing test focuses you even more quickly and recruits your own memory for help in recreating the feeling of motion more quickly. It's like a way to leave the car running in second gear.

I'm trying to help my students, who are mostly still learning how to write code, learn how to get started when they program. Many of them seem repeatedly to find themselves sitting still, grinding their gears and trying to figure out how to write the next bit of code and get it running. Ultimately, the answer may come down to the same thing we learn when we learn to drive a stick: practice, practice, practice, and eventually you get the feel of how the gearshift works.


Posted by Eugene Wallingford | Permalink | Categories: General, Software Development

September 05, 2012 5:24 PM

Living with the Masters

I sometimes feel guilty that most of what I write here describes connections between teaching or software development and what I see in other parts of the world. These connections are valuable to me, though, and writing them down is valuable in another way.

I'm certainly not alone. In Why Read, Mark Edmondson argues for the value of reading great literature and trying on the authors' view of the world. Doing so enables us to better understand our own view of the world, It also gives us the raw material out of which to change our worldview, or build a new one, when we encounter better ideas. In the chapter "Discipline", Edmondson writes:

The kind of reading that I have been describing here -- the individual quest for what truth a work reveals -- is fit for virtually all significant forms of creation. We can seek vital options in any number of places. They may be found for this or that individual in painting, in music, in sculpture, in the arts of furniture making or gardening. Thoreau felt he could derive a substantial wisdom by tending his bean field. He aspired to "know beans". He hoed for sustenance, as he tells us, but he also hoed in search of tropes, comparisons between what happened in the garden and what happened elsewhere in the world. In his bean field, Thoreau sought ways to turn language -- and life -- away from old stabilities.

I hope that some of my tropes are valuable to you.

The way Edmondson writes of literature and the liberal arts applies to the world of software in a much more direct ways too. First, there is the research literature of computing and software development. One can seek truth in the work of Alan Kay, David Ungar, Ward Cunningham, or Kent Beck. One can find vital options in the life's work of Robert Floyd, Peter Landin, or Alan Turing; Herbert Simon, Marvin Minsky, or John McCarthy. I spent much of my time in grad school immersed in the writings and work of B. Chandrasekaran, which affected my view of intelligence in both humans and machines.

Each of these people offers a particular view into a particular part of the computing world. Trying out their worldviews can help us articulate our own worldviews better, and in the process of living their truths we sometimes find important new truths for ourselves.

We in computing need not limit ourselves to the study of research papers and books. As Edmondson says the individual quest for the truth revealed in a work "is fit for virtually all significant forms of creation". Software is a significant form of creation, one not available to our ancestors even sixty years ago. Live inside any non-trivial piece of software for a while, especially one that has withstood the buffets of human desire over a period of time, and you will encounter truth -- truths you find there, and truths you create for yourself. A few months trying on Smalltalk and its peculiar view of the world taught me OOP and a whole lot more.


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

September 01, 2012 10:18 AM

Making Assumptions

a dartboard

Patrick Honner has been writing a series of blog posts reviewing problems from the June 2012 New York State Math Regents exams. A recent entry considered a problem in which students were asked to compute the probability that a dart hits the bull's eye on a dartboard. This question requires the student to make a specific assumption: "that every point on the target is equally likely to be hit". Honner writes:

... It's not necessarily bad that we make such assumptions: refining and simplifying problems so they can be more easily analyzed is a crucial part of mathematical modeling and problem solving.

What's unfortunate is that, in practice, students are kept outside this decision-making process: how and why we make such assumptions isn't emphasized, which is a shame, because exploring such assumptions is a fundamental mathematical process.

The same kinds of assumptions are built into even the most realistic problems that we set before our students. But discussing assumptions is an essential part of doing math. Which assumptions are reasonable? Which are necessary? What is the effect of a particular assumption on the meaning of the problem, on the value of the answer we will obtain? This kind of reasoning is, in many ways, the real math in a problem. Once we have a formula or two, we are down to crunching numbers. That's arithmetic.

Computer science teachers face the risks when we pose problems to our students, including programming problems. Discovering the boundaries of a problem and dealing with the messy details that live on the fringe are an essential part of making software. When we create assignments that can be neatly solved in a week or two, we hide "a fundamental computing process" from our students. We also rob them of a lot of fun.

As Honner says, though, making assumptions is not necessarily bad. In the context of teaching a course, they are necessary. Sometimes, we need to focus our students' attention on a specific new skill to be learned or honed. Tidying up the boundaries of a problem bring that skill into greater relief and eliminate what are at the moment unnecessary distractions.

It is important, though, for a computing curriculum to offer students increasing opportunities to confront the assumptions we make and begin to make assumptions for themselves. That level of modeling is also a specific skill to be learned and honed. It also can make class more fun for the professor, if a lot messier when it comes time to evaluating student work and assigning grades.

Even when we have to make assumptions prior to assigning a problem, discussing them explicitly with students can open their eyes to the rest of the complexity in making software. Besides, some students already sense or know that we are hiding details from them, and having the discussion is a way to honor their knowledge -- and earn their respect.

So, the next time you assign a problem, ask yourself: What assumptions have I made in simplifying this problem? Are they necessary? If not, can I loosen them? If yes, can my students benefit from discussing them?

And be prepared... If you leave a few messy assumptions lying around a problem for your students to confront and make on their own, some students will be unhappy with you. As Honner says, we teachers spend a lot of time training students to make implicit assumptions unthinkingly. In some ways, we are too successful for our own good.


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

August 31, 2012 3:22 PM

Two Weeks Along the Road to OOP

The month has flown by, preparing for and now teaching our "intermediate computing" course. Add to that a strange and unusual set of administrative issues, and I've found no time to blog. I did, however manage to post what has become my most-retweeted tweet ever:

I wish I had enough money to run Oracle instead of Postgres. I'd still run Postgres, but I'd have a lot of cash.

That's an adaptation of tweet originated by @petdance and retweeted my way by @logosity. I polished it up, sent it off, and -- it took off for the sky. It's been fun watching its ebb and flow, as it reaches new sub-networks of people. From this experience I must learn at least one lesson: a lot of people are tired of sending money to Oracle.

The first two weeks of my course have led the students a few small steps toward object-oriented programming. I am letting the course evolve, with a few guiding ideas but no hard-and-fast plan. I'll write about the course's structure after I have a better view of it. For now, I can summarize the first four class sessions:

  1. Run a simple "memo pad" app, trying to identify behavior (functions) and state (persistent data). Discuss how different groupings of the functions and data might help us to localize change.
  2. Look at the code for the app. Discuss the organization of the functions and data. See a couple of basic design patterns, in particular the separation of model and view.
  3. Study the code in greater detail, with a focus on the high-level structure of an OO program in Java.
  4. Study the code in greater detail, with a focus on the lower-level structure of classes and methods in Java.

The reason we can spend so much time talking about a simple program is that students come to the course without (necessarily) knowing any Java. Most come with knowledge of Python or Ada, and their experiences with such different languages creates an interesting space in which to encounter Java. Our goal this semester is for students to learn their second language as much as possible, rather than having me "teach" it to them. I'm trying to expose them to a little more of the language each day, as we learn about design in parallel. This approach works reasonably well with Scheme and functional programming in a programming languages course. I'll have to see how well it works for Java and OOP, and adjust accordingly.

Next week we will begin to create things: classes, then small systems of classes. Homework 1 has them implementing a simple array-based class to an interface. It will be our first experience with polymorphic objects, though I plan to save that jargon for later in the course.

Finally, this is the new world of education: my students are sending me links to on-line sites and videos that have helped them learn programming. They want me to check them and and share with the other students. Today I received a link to The New Boston, which has among its 2500+ videos eighty-seven beginning Java and fifty-nine intermediate Java titles. Perhaps we'll come to a time when I can out-source all instruction on specific languages and focus class time on higher-level issues of design and programming...


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

August 13, 2012 3:56 PM

Lessons from Unix for OO Design

Pike's and Kernighan's Program Design in the UNIX Environment includes several ideas I would like for my students to learn in my Intermediate Computing course this fall. Among them:

... providing the function in a separate program makes convenient options ... easier to invent, because it isolates the problem as well as the solution.

In OO, objects are the packages that create possibilities for us. The beauty of this lesson is the justification: because a class isolates the problem as well as the solution.

This solution affects no other programs, but can be used with all of them.

This is one of the great advantages of polymorphic objects.

The key to problem-solving on the UNIX system is to identify the right primitive operations and to put them at the right place.

Methods should live in the objects whose data they manipulate. One of the hard lessons for novice OO programmers coming from a procedural background is putting methods with the thing, not a faux actor.

UNIX programs tend to solve general problems rather than special cases.

Objects that are too specific should be rare, at least for beginning programmers. Specificity in interface often indicates that implementation detail is leaking out.

Merely adding features does not make it easier for users to do things -- it just makes the manual thicker.

Keep objects small and focused. A big interface is often evidence of an object waiting to be born.

~~~~

In many ways, The Unix Way is contrary to object-oriented programming. Or so many of Linux friends tell me. But I'm quite comfortable with the parallels found in these quotes, because they are more about good design in general than about Unix or OOP themselves.


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

July 23, 2012 3:14 PM

Letting Go of Old Strengths

Ward Cunningham commented on what it's like to be "an old guy who's still a programmer" in his recent Dr. Dobb's interview:

A lot of people think that you can't be old and be good, and that's not true. You just have to be willing to let go of the strengths that you had a year ago and get some new strengths this year. Because it does change fast, and if you're not willing to do that, then you're not really able to be a programmer.""

That made me think of the last comment I made in my posts on JRubyConf:

There is a lot of stuff I don't know. I won't run out of things to read and learn and do for a long, long, time.

This is an ongoing theme in the life of a programmer, in the life of a teacher, and the life of an academic: the choice we make each day between keeping up and settling down. Keeping up is a lot more fun, but it's work. If you aren't comfortable giving up what you were awesome at yesterday, it's even more painful. I've been lucky mostly to enjoy learning new stuff more than I've enjoyed knowing the old stuff. May you be so lucky.


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

July 16, 2012 3:02 PM

Refactoring Everywhere: In Code and In Text

Charlie Stross is a sci-fi writer. Some of my friends have recommended his fiction, but I've not read any. In Writing a novel in Scrivener: lessons learned, he, well, describes what he has learned writing novels using Scrivener, an app for writers well known in the Mac OS X world.

I've used it before on several novels, notably ones where the plot got so gnarly and tangled up that I badly needed a tool for refactoring plot strands, but the novel I've finished, "Neptune's Brood", is the first one that was written from start to finish in Scrivener...

... It doesn't completely replace the word processor in my workflow, but it relegates it to a markup and proofing tool rather than being a central element of the process of creating a book. And that's about as major a change as the author's job has undergone since WYSIWYG word processing came along in the late 80s....

My suspicion is that if this sort of tool spreads, the long-term result may be better structured novels with fewer dangling plot threads and internal inconsistencies. But time will tell.

Stross's lessons don't all revolve around refactoring, but being able to manage and manipulate the structure of the evolving novel seems central to his satisfaction.

I've read a lot of novels that seemed like they could have used a little refactoring. I always figured it was just me.

The experience of writing anything in long form can probably be improved by a good refactoring tool. I know I find myself doing some pretty large refactorings when I'm working on the set of lecture notes for a course.

Programmers and computer scientists have the advantage of being more comfortable writing text in code, using tools such as LaTex and Scribble, or homegrown systems. My sense, though, is that fewer programmers use tools like this, at least at full power, than might benefit from doing so.

Like Stross, I have a predisposition against using tools with proprietary data formats. I've never lost data stored in plaintext to version creep or application obsolescence. I do use apps such as VoodooPad for specific tasks, though I am keenly aware of the exit strategy (export to text or RTFD ) and the pain trade-off at exit (the more VoodooPad docs I create, the more docs I have to remember to export before losing access to the app). One of the things I like most about MacJournal is that it's nothing but a veneer over a set of Unix directories and RTF documents. The flip side is that it can't do for me nearly what Scrivener can do.

Thinking about a prose writing tool that supports refactoring raises an obvious question: what sort of refactoring operations might it provide automatically? Some of the standard code refactorings might have natural analogues in writing, such as Extract Chapter or Inline Digression.

Thinking about automated support for refactoring raises another obvious question, the importance of which is surely as clear to novelists as to software developers: Where are the unit tests? How will we know we haven't broken the story?

I'm not being facetious. The biggest fear I have when I refactor a module of a course I teach is that I will break something somewhere down the line in the course. Your advice is welcome!


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

July 11, 2012 2:45 PM

A Few Comments on the Alan Kay Interview, and Especially Patterns

Alan Kay

Many of my friends and colleagues on Twitter today are discussing the Interview with Alan Kay posted by Dr. Dobb's yesterday. I read the piece this morning while riding the exercise bike and could not contain my desire to underline passages, star paragraphs, and mark it up with my own comments. That's hard to do while riding hard, hurting a little, and perspiring a lot. My desire propelled me forward in the face of all these obstacles.

Kay is always provocative, and in this interview he leaves no oxen ungored. Like most people do when whenever they read outrageous and provocative claims, I cheered when Kay said something I agreed with and hissed -- or blushed -- when he said something that gored me or one of my pet oxen. Twitter is a natural place to share one's cheers and boos for an artyicle with or by Alan Kay, given the amazing density of soundbites one finds in his comments about the world of computing.

(One might say the same thing about Brian Foote, the source of both soundbites in that paragraph.)

I won't air all my cheers and hisses here. Read the article, if you haven't already, and enjoy your own. I will comment on one paragraph that didn't quite make me blush:

The most disastrous thing about programming -- to pick one of the 10 most disastrous things about programming -- there's a very popular movement based on pattern languages. When Christopher Alexander first did that in architecture, he was looking at 2,000 years of ways that humans have made themselves comfortable. So there was actually something to it, because he was dealing with a genome that hasn't changed that much. I think he got a few hundred valuable patterns out of it. But the bug in trying to do that in computing is the assumption that we know anything at all about programming. So extracting patterns from today's programming practices ennobles them in a way they don't deserve. It actually gives them more cachet.

Long-time Knowing and Doing readers know that patterns are one of my pet oxen, so it would have been natural for me to react somewhat as Keith Ray did and chide Kay for what appears to be a typical "Hey, kids, get off my lawn!" attitude. But that's not my style, and I'm such a big fan of Kay's larger vision for computing that my first reaction was to feel a little sheepish. Have I been wasting my time on a bad idea, distracting myself from something more important? I puzzled over this all morning, and especially as I read other people's reactions to the interview.

Ultimately, I think that Kay is too pessimistic when he says we hardly know anything at all about programming. We may well be closer to the level of the Egyptians who built the pyramids than we are to the engineers who built the Empire State Building. But I simply don't believe that people such as Ward Cunningham, Ralph Johnson, and Martin Fowler don't have a lot to teach most of us about how to make better software.

Wherever we are, I think it's useful to identify, describe, and catalog the patterns we see in our software. Doing so enables us to talk about our code at a level higher than parentheses and semicolons. It helps us bring other programmers up to speed more quickly, so that we don't all have to struggle through all the same detours and tar pits our forebears struggled through. It also makes it possible for us to talk about the strengths and weaknesses of our current patterns and to seek out better ideas and to adopt -- or design -- more powerful languages. These are themes Kay himself expresses in this very same interview: the importance of knowing our history, of making more powerful languages, and of education.

Kay says something about education in this interview that is relevant to the conversation on patterns:

Education is a double-edged sword. You have to start where people are, but if you stay there, you're not educating.

The real bug in what he says about patterns lies at one edge of the sword. We may not know very much about how to make software yet, but if we want to remedy that, we need to start where people are. Most software patterns are an effort to reach programmers who work in the trenches, to teach them a little of what we do know about how to make software. I can yammer on all I want about functional programming. If a Java practitioner doesn't appreciate the idea of a Value Object yet, then my words are likely wasted.

Ward Cunningham

Ironically, many argue that the biggest disappointment of the software patterns effort lies at the other edge of education's sword: an inability to move the programming world quickly enough from where it was in the mid-1990s to a better place. In his own Dr. Dobb's interview, Ward Cunningham observed with a hint of sadness that an unexpected effect of the Gang of Four Design Patterns book was to extend the life of C++ by a decade, rather than reinvigorating Smalltalk (or turning people on to Lisp). Changing the mindset of a large community takes time. Many in the software patterns community tried to move people past a static view of OO design embodied in the GoF book, but the vocabulary calcified more quickly than they could respond.

Perhaps that is all Kay meant by his criticism that patterns "ennoble" practices in a way they don't deserve. But if so, it hardly qualifies in my mind as "one of the 10 most disastrous things about programming". I can think of a lot worse.

Kurt Vonnegut

To all this, I can only echo the Bokononists in Kurt Vonnegut's novel Cat's Cradle: "Busy, busy, busy." The machinery of life is usually more complicated and unpredictable than we expect or prefer. As a result, reasonable efforts don't always turn out as we intend them to. So it goes. I don't think that means we should stop trying.

Don't let my hissing about one paragraph in the interview dissuade you from reading the Dr. Dobb's interview. As usual, Kay stimulates our minds and encourages us to do better.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Patterns, Software Development

July 06, 2012 4:19 PM

Assume a Good Compiler and Write Readable Code

Greg Robbins and Ron Avitzur, the authors of MacOS's original Graphing Calculator, offer nine tips for Designing Applications for the Power Macintosh. All of them are useful whatever your target machine. One of my favorites is:

5. Avoid programming cleverness. Instead, assume a good compiler and write readable code.

This is good programming advice in nearly every situation, for all the software engineering reasons we know. Perhaps surprisingly, it is good advice even when you are writing code that has to be fast and small, as Robbins and Avitzur were:

Cycle-counting and compiler-specific optimizations are favorite pastimes of hackers, and sometimes they're important. But we could never have completed the Graphing Calculator in under six months had we worried about optimizing each routine. Rather, we dealt with speed problems only when they were perceptible to users.

We made no attempt to look at performance bottlenecks or at the compiled code of the Calculator until after running execution profiles. We were surprised where the time was being spent. Most of the time that the Calculator is compute-bound it's either in the math libraries or in QuickDraw. So little time is spent in our code that even compiling it unoptimized didn't slow it down perceptibly. Improving our code's performance meant calling the math libraries less often.

This has been my experience with every large program or set of programs I've written, too. I know where the code is spending its time. Then I run the profiler, and it shows me I'm wrong. Donald Knuth famously warned us against small efficiencies and premature optimization.

Robbins and Avitzur's advice also has a user-centered dimension.

Programmers are often tempted to spend time saving a few bytes or cycles or to fine-tune an algorithm. If the change isn't visible to users, however, the benefits may not extend beyond the programmer's satisfaction. When most of the code in an application is straightforward and readable, maintenance and improvements are easier to make. Those are changes that users will notice.

We write code for our users. Programmer satisfaction comes second. This passage reminds me of a lesson I internalized from the early days extreme programming: At the end of the day, if you haven't added value for your customer, you haven't earned your day's pay.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

July 03, 2012 3:28 PM

A Little Zen, A Little Course Prep

I listened to about 3/4 of Zen and the Art of Motorcycle Maintenance on a long-ish drive recently. It's been a while since I've read the whole book, but I listen to it on tape once a year or so. It always gets my mind in the mood to think about learning to read, write, and debug programs.

This fall, I will be teaching our third course for first time since became head seven years ago. In that time, we changed the name of the course from "Object-Oriented Programming" to "Intermediate Computing". In many ways, the new name is an improvement. We want students in this course to learn a number of skills and tools in the service of writing larger programs. At a fundamental level, though OOP remains the centerpiece of everything we do in the course.

As I listened to Pirsig make his way across the Great Plains, a few ideas stood out as prepare to teach one of my favorite courses:

The importance of making your own thing, not just imitating others. This is always a challenge in programming courses, but for most people it is essential if we hope for students to maximize their learning. It underlies several other parts of Pirsig's zen and art, such as caring about our artifacts, and the desire to go beyond what something is to what it means.

The value of reading code, both good and bad. Even after only one year of programming, most students have begun to develop a nose for which is which, and nearly all have enough experience that they can figure out the difference with minimal interference from the instructor. If we can get them thinking about what features of a program make it good or bad, we can move on to the more important question: How can we write good programs? If we can get students to think about this, then they can see the "rules" we teach them for what they really are: guidelines, heuristics that point us in the direction of good code. They can learn the rules with an end in mind, and not as an end in themselves.

The value of grounding abstractions in everyday life. When we can ground our classwork in their own experiences, they are better prepared to learn from it. Note that this may well involve undermining their naive ideas about how something works, or turning a conventional wisdom from their first year on its head. The key is to make what they see and do matter to them.

One idea remains fuzzy in my head but won't let me go. While defining the analytic method, Pirsig talks briefly about the difference between analysis by composition and analysis by function. Given that this course is teaches object-oriented programming in Java, there are so many ways in which this distinction could matter: composition and inheritance, instance variables and methods, state and behavior. I'm not sure whether there is anything particular useful in Pirsig's philosophical discussion of this, so I'll think some more about it.

I'm also thinking a bit about a non-Zen idea for the course: Mark Guzdial's method of worked examples and self-explanation. My courses usually include a few worked examples, but Mark has taken the idea to another level. More important, he pairs it with an explicit step in which students explain examples to themselves and others. This draws on results from research in CS education showing that learning and retention are improved when students explain something in their own words. I think this could be especially valuable in a course that asks students to learn a new style of writing code.

One final problem is on my mind right now, a more practical matter: a textbook for the course. When I last taught this course, I used Tim Budd's Understanding Object-Oriented Programming with Java. I have written in the past that I don't like textbooks much, but I always liked this book. I liked the previous multi-language incarnation of the book even more. Unfortunately, one of the purposes of this course is to have students learn Java reasonably well.

Also unfortunate is that Budd's OOP/Java book is now twelve years old. A lot has happened in the Java world in the meantime. Besides, as I found while looking for a compiler textbook last fall, the current asking price of over $120 seems steep -- especially for a CS textbook published in 2000!

So I persist in my quest. I'd love to find something that looks like it is from this century, perhaps even reflecting the impending evolution of the textbook we've all been anticipating. Short of that, I'm looking for a modern treatment of both OO principles and Java.

Of course, I'm a guy who still listens to books on tape, so take my sense of what's modern with a grain of salt.

As always, any pointers and suggestions are appreciated.


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

June 28, 2012 4:13 PM

"Doing research is therefore writing software."

The lede from RA Manual: Notes on Writing Code, by Gentzkow and Shapiro:

Every step of every research project we do is written in code, from raw data to final paper. Doing research is therefore writing software.

The authors are economists at the University of Chicago. I have only skimmed the beginning of the paper, but I like what little I've seen. They take seriously the writing of computer programs.

  • "This document lays out some broad principles we should all follow."
  • "We encourage you to invest in reading more broadly about software craftsmanship, looking critically at your own code and that of your colleagues, and suggesting improvements or additions to the principles below."
  • "Apply these principles to every piece of code you check in without exception."
  • "You should also take the time to improve code you are modifying or extending even if you did not write the code yourself."

...every piece of code you check in... Source code management and version control? They are a couple of steps up on many CS professors and students.

Thanks to Tyler Cowen for the link.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

June 28, 2012 12:37 PM

What Big Software Needs

Unix guru Rob Pike, on "programming in the large":

There's this idea about "programming in the large" and somehow C++ and Java own that domain. I believe that's just a historical accident, or perhaps an industrial accident. But the widely held belief is that it has something to do with object-oriented design.

Big software needs methodology to be sure, but not nearly as much as it needs strong dependency management and clean interface abstraction and superb documentation tools, none of which is served well by C++ (although Java does noticeably better).

That is as succinct a summary as I've seen of what people need from a language in order to write and maintain large programs: strong dependency management, clean interface abstraction, and superb documentation tools. I think that individuals and small teams need them as much as large teams, but that you experience the pain of not having them much sooner when you work on larger teams.

the logo of the Go programming language

The quoted passage is from Less is exponentially more, the text of a talk he gave this month about the biggest surprise he experienced from the rolling out of Go, the programming language he and several colleagues created at Google. He had expected Go to attract C and C++ programmers, because Go was designed to do the things that C++ is used for. Instead, it attracts programmers from Python and Ruby. I'm tempted to quote Pike's conclusion, because it's so succinct, but instead I'll let you read his blog post yourself.

It was interesting to read this paper the day after seeing Leo Meyerovich's blog post on the sociology of programming languages. After reading Pike's thoughts on the spread of Go, I'm more motivated to read the paper Meyerovich introduces, on the principles for programming language adoption.

Irrespective of the adoption question: Pike's talk has no code in it, yet it conveys the spirit of Go better than anything I had read before.

~~~~

Go logo comes courtesy of the project's open-source repository at Google Code.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

June 25, 2012 12:11 PM

Test-First Development and Implementation of Processing.js

While describing the lessons learned by the team that wrote Processing.js, Mike Kamermans talks about one of the benefits of writing tests before writing code:

The usual process, in which code is written and then test cases are written for that code, actually creates biased tests. Rather than testing whether or not your code does what it should do, according to the specification, you are only testing whether your code is bug-free. In Processing.js, we instead start by creating test cases based on what the functional requirements for some function or set of functions is, based on the documentation for it. With these unbiased tests, we can then write code that is functionally complete, rather than simply bug-free but possibly deficient.

When you implement a language processor, you can use the language specification as a primary guide. Testing your code efficiently, though, means translating the features of the spec into test cases -- code. When you port a language from one platform to another, you can usually use the documentation of the original implementation as a guide, too. The Processing.js team had the benefit that the original implementation also came with a large set of test cases. This allowed them to write code against tests from the beginning, and then write their own tests before writing code that went beyond the scope of the original.

The next time I teach our compiler course, I hope to do a better job getting students to write tests sooner, if not first, as a matter of habit. Perhaps I will seed the teams with a few tests to help them get started.

~~~~

The passage above comes from the chapter on Processing.js in Volume 2 of The Architecture of Open Source Applications. This was a good read that taught me a bit about Javascript, HTML 5, and the web browser as a platform. But most of all it explained the thought process that went into porting a powerful Java package to an architecture with considerably different strengths and weakness. Language theory is all fine and good, but language implementors have to make pragmatic choices in the service of users. It's essential to remember that, in the end, what matters is that the compiler or interpreter produce correct results -- and not, in the case of a port, that the resulting code resemble the original (another lesson the Processing.js team learned).

Another lesson this chapter teaches is to acknowledge when when program doesn't meet everyone's expectations. This was a serious challenge for Processing.js, because Java makes possible behaviors that a web browser does not. When you can't make something work the way people expect, tell them. Processing.js provides documentation for people who come to it with a Processing background, and documentation for people who come to it with a JavaScript background.

Next up on my reading list from AOSA: the design of LLVM.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

June 19, 2012 3:04 PM

Basic Arithmetic, APL-Style, and Confident Problem Solvers

After writing last week about a cool array manipulation idiom, motivated by APL, I ran across another reference to "APL style" computation yesterday while catching up with weekend traffic on the Fundamentals of New Computing mailing list. And it was cool, too.

Consider the sort of multi-digit addition problem that we all spend a lot of time practicing as children:

        365
     +  366
     ------

The technique requires converting two-digit sums, such as 6 + 5 = 11 in the rightmost column, into a units digit and carrying the tens digit into the next column to the left. The process is straightforward but creates problems for many students. That's not too surprising, because there is a lot going on in a small space.

David Leibs described a technique, which he says he learned from something Kenneth Iverson wrote, that approaches the task of carrying somewhat differently. It takes advantage of the fact that a multi-digit number is a vector of digits times another vector of powers.

First, we "spread the digits out" and add them, with no concern for overflow:

        3   6   5
     +  3   6   6
     ------------
        6  12  11

Then we normalize the result by shifting carries from right to left, "in fine APL style".

        6  12  11
        6  13   1
        7   3   1

According to Leibs, Iverson believed that this two-step approach was easier for people to get right. I don't know if he had any empirical evidence for the claim, but I can imagine why it might be true. The two-step approach separates into independent operations the tasks of addition and carrying, which are conflated in the conventional approach. Programmers call this separation of concerns, and it makes software easier to get right, too.

Multiplication can be handled in a conceptually similar way. First, we compute an outer product by building a digit-by-digit times table for the digits:

     +---+---------+
     |   |  3  6  6|
     +---+---------+
     | 3 |  9 18 18|
     | 6 | 18 36 36|
     | 5 | 15 30 30|
     +---+---------+

This is straightforward, simply an application of the basic facts that students memorize when they first learn multiplication.

Then we sum the diagonals running southwest to northeast, again with no concern for carrying:

     (9) (18+18) (18+36+15) (36+30) (30)
      9      36         69      66   30

In the traditional column-based approach, we do this implicitly when we add staggered columns of digits, only we have to worry about the carries at the same time -- and now the carry digit may be something other than one!

Finally, we normalize the resulting vector right to left, just as we did for addition:

         9  36  69  66  30
         9  36  69  69   0
         9  36  75   9   0
         9  43   5   9   0
        13   3   5   9   0
     1   3   3   5   9   0

Again, the three components of the solution are separated into independent tasks, enabling the student to focus on one task at a time, using for each a single, relatively straightforward operator.

(Does this approach remind some of you of Cannon's algorithm for matrix multiplication in a two-dimensional mesh architecture?)

Of course, Iverson's APL was designed around vector operations such as these, so it includes operators that make implementing such algorithms as straightforward as the calculate-by-hand technique. Three or four Greek symbols and, voilá, you have a working program. If you are Dave Ungar, you are well on your way to a compiler!

the cover of High-Speed Math Self-Taught, by Lester Meyers

I have a great fondness for alternative ways to do arithmetic. One of the favorite things I ever got from my dad was a worn copy of Lester Meyers's High-Speed Math Self-Taught. I don't know how many hours I spent studying that book, practicing its techniques, and developing my own shortcuts. Many of these techniques have the same feel as the vector-based approaches to addition and multiplication: they seem to involve more steps, but the steps are simpler and easier to get right.

A good example of this I remember learning from High-Speed Math Self-Taught is a shortcut for finding 12.5% of a number: first multiply by 100, then divide by 8. How can a multiplication and a division be faster than a single multiplication? Well, multiplying by 100 is trivial: just add two zeros to the number, or shift the decimal point two places to the right. The division that remains involves a single-digit divisor, which is much easier than multiplying by a three-digit number in the conventional way. The three-digit number even has its own decimal point, which complicates matters further!

To this day, I use shortcuts that Meyers taught me whenever I'm making updating the balance in my checkbook register, calculating a tip in a restaurant, or doing any arithmetic that comes my way. Many people avoid such problems, but I seek them out, because I have fun playing with the numbers.

I am able to have fun in part because I don't have to worry too much about getting a wrong answer. The alternative technique allows me to work not only faster but also more accurately. Being able to work quickly and accurately is a great source of confidence. That's one reason I like the idea of teaching students alternative techniques that separate concerns and thus offer hope for making fewer mistakes. Confident students tend to learn and work faster, and they tend to enjoy learning more than students who are handcuffed by fear.

I don't know if anyone was tried teaching Iverson's APL-style basic arithmetic to children to see if it helps them learn faster or solve problems more accurately. Even if not, it is both a great demonstration of separation of concerns and a solid example of how thinking about a problem differently opens the door to a new kind of solution. That's a useful thing for programmers to learn.

~~~~

Postscript. If anyone has a pointer to a paper or book in which Iverson talks about this approach to arithmetic, I would love to hear from you.

IMAGE: the cover of Meyers's High-Speed Math Self-Taught, 1960. Source: OpenLibrary.org.


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

June 13, 2012 2:19 PM

The First Rule of Programming in Ruby

When I was thinking about implementing the cool programming idiom I blogged about yesterday, I forgot the first rule of programming in Ruby:

It's already in there.

It didn't take long after my post went live that readers began to point out that Ruby already offers the functionality of my sub and R's { operator, via Array#values_at:

     >> [10, 5, 9, 6, 20, 17, 1].values_at(6, 1, 3, 2, 0, 5, 4)
     =;> [1, 5, 6, 9, 10, 17, 20]

I'm not surprised. I should probably spend a few minutes every day browsing the documentation for a randomly-chosen Ruby class. There's so much to find! There's also too much to remember out of context, but I never know when I'll come across a need and have a vague recollection that Ruby already does what I need.

Reader Gary Wright pointed out that I can get closer to R's syntax by aliasing values_at with an unused array operator, say:

     class Array
       def %(*args)
         values_at(*args.first)
       end
     end

Now my use of % is as idiomatic in Ruby as { is in R:

     >> [10, 5, 9, 6, 20, 17, 1] % [6, 1, 3, 2, 0, 5, 4]
     =;> [1, 5, 6, 9, 10, 17, 20]

I am happy to learn that Ruby already has my method and am just as happy to have spent time thinking about and implementing it on my own. I like to play with the ideas as much as I like knowing the vast class library of a modern scripting language.

(If I were writing Ruby code for a living, my boss might not look upon my sense of exploration so favorably... There are advantages to being an academic!)


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

June 12, 2012 3:44 PM

Faking a Cool Programming Idiom in Ruby

Last week, James Hague blogged about a programming idiom you've never heard of: fetching multiple items from an array with a single operation.

Let's say the initial array is this:
     10 5 9 6 20 17 1

Fetching the values at indices 0, 1, 3, and 6, gives:

     10 5 6 1

You can do this directly in APL-style languages such as J and R. In J, for example, you use the { operator:

     0 1 3 6 { 10 5 9 6 20 17 1

Such an operator enables you to do some crazy things, like producing a sorted array by accessing it with a permuted set of indices. This:

     6 1 3 2 0 5 4 { 10 5 9 6 20 17 1

produces this:

     1 5 6 9 10 17 20

When I saw this, my first thought was, "Very cool!" It's been a long time since I programmed in APL, and if this is even possible in APL, I'd forgotten.

One of my next thoughts was, "I bet I can fake that in Ruby...".

I just need a way to pass multiple indices to the array, invoking a method that fetches one value at a time and returns them all. So I created an Array method named sub that takes the indices as an array.

     class Array
       def sub slots
         slots.map {|i| self[i] }
       end
     end

Now I can say:

     [10, 5, 9, 6, 20, 17, 1].sub([6, 1, 3, 2, 0, 5, 4])

and produce [1, 5, 6, 9, 10, 17, 20].

The J solution is a little cleaner, because my method requires extra syntax to create an array of indices. We can do better by using Ruby's splat operator, *. splat gathers up loose arguments into a single collection.

     class Array
       def sub(*slots)             # splat the parameter
         slots.map {|i| self[i] }
       end
     end

This definition allows us to send sub any number of integer arguments, all of which will be captured into the parameter slots.

Now I can produce the sorted array by saying:

     [10, 5, 9, 6, 20, 17, 1].sub(6, 1, 3, 2, 0, 5, 4)

Of course, Ruby allows us to omit the parentheses when we send a message as long as the result is unambiguous. So we can go one step further:

     [10, 5, 9, 6, 20, 17, 1].sub 6, 1, 3, 2, 0, 5, 4

Not bad. We are pretty close to the APL-style solution now. Instead of {, we have .sub. And Ruby requires comma-separated argument lists, so we have to use commas when we invoke the method. These are syntactic limitations placed on us by Ruby.

Still, with relative simple code we are able to fake Hague's idiom quite nicely. With a touch more complexity, we could write sub to allow either the unbundled indices or a single array containing all the indices. This would make the code fit nicely with other Ruby idioms that produce array values.

If you have stronger Ruby-fu than I and can suggest a more elegant implementation, please share. I'd love to learn something new!


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

June 05, 2012 3:33 PM

Writing and Rewriting

An interviewer once asked writer Stephen King about extensive rewrites, and King responded:

One of the ways the computer has changed the way I work is that I have a much greater tendency to edit "in the camera" -- to make changes on the screen. With 'Cell' that's what I did. I read it over, I had editorial corrections, I was able to make my own corrections, and to me that's like ice skating. It's an OK way to do the work, but it isn't optimal. With 'Lisey' I had the copy beside the computer and I created blank documents and retyped the whole thing. To me that's like swimming, and that's preferable. It's like you're writing the book over again. It is literally a rewriting.

The idea of typing an existing text made me think of Zed Shaw's approach to teaching programming, which has grown into Learn Code the Hard Way. You can learn a lot about a body of words or code by reading it just enough to type it, and letting your brain do the rest. I'm not sure how well this approach would work for a group of complete novices. I suspect that a few would like it and that many would not. I like having it around, though, because I like having as diverse a set of tools as possible for reaching students.

For someone who already knows how to write -- or, in King's case, who actually wrote the text he is retyping -- the act offers a different set of trade-offs than rewriting or refactoring in place. It also offers a very different experience from (re)writing from scratch, or deleting text so you won't be tempted to keep it.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

May 29, 2012 2:44 PM

Some Final Thoughts and Links from JRubyConf

You are probably tired of hearing me go on about JRubyConf, so I'll try to wrap up with one more post. After the first few talks, the main result of the rest of conference was to introduced me to several cool projects and a few interesting quotes.

Sarah Allen speaking on agile business development

Sarah Allen gave a talk on agile business development. Wow, she has been part of creating several influential pieces of software, including AfterEffects, ShockWave, and FlashPlayer. She talked a bit about her recent work to increase diversity among programmers and reminded us that diversity is about more than the categories we usually define:

I may be female and a minority here, but I'm way more like everybody in here than everybody out there.

Increasing diversity means making programming accessible to people who wouldn't otherwise program.

Regarding agile development, Sarah reminded us that agile's preference for working code over documentation is about more than just code:

Working code means not only "passes the tests" but also "works for the customer".

... which is more about being the software they need than simply getting right answers to some tests written in JUnit.

Nate Schutta opened day two with a talk on leading technical change. Like Venkat Subramaniam on day one, Schutta suggested that tech leaders consider management's point of view when trying to introduce new technology, in particular the risks that managers face. If you can tie new technology to the organization's strategic goals and plans, then managers can integrate it better into other actions. Schutta attributed his best line to David Hussman:

Change must happen with people, not to them.

The award for the conference's most entertaining session goes to Randall Thomas and Tammer Saleh for "RUBY Y U NO GFX?", their tag-team exegesis of the history of computer graphics and where Ruby fits into that picture today. They echoed several other speakers in saying that JRuby is the bridge to the rest of the programming world that Ruby programmers need, because the Java community offers so many tools. For example, it had never occurred to me to use JRuby to connect my Ruby code to Processing, the wonderful open-source language for programming images and animations. (I first mentioned Processing here over four years ago in its original Java form, and most recently was thinking of its JavaScript implementation.)

Finally, a few quickies:

  • Jim Remsik suggested Simon Sinek's TED talk, How great leaders inspire action, with the teaser line, It's not what you do; it's why you do it.

  • Yoko Harada introduced me to Nokogiri, a parser for HTML, XML, and the like.

  • Andreas Ronge gave a talk on graph databases as a kind of NoSQL database and specifically about Neo4j.rb, his Ruby wrapper on the Java library Neo4J.

  • I learned about Square, which operates in the #fintech space being explored by the Cedar Valley's own T8 Webware and by Iowa start-up darling Dwolla.

  • rapper Jay Z
    I mentioned David Wood in yesterday's entry. He also told a great story involving rapper Jay-Z, illegal music downloads, multi-million-listener audiences, Coca Cola, logos, and video releases that encapsulated in a nutshell the new media world in which we live. It also gives a very nice example of why Jay-Z will soon be a billionaire, if he isn't already. He gets it.

  • The last talk I attended before hitting the road was by Tony Arcieri, on concurrent programming in Ruby, and in particular his concurrency framework Celluloid. It is based on the Actor model of concurrency, much like Erlang and Scala's Akka framework. Regarding these two, Arcieri said that Celluloid stays truer the original model's roots than Akka by having objects at its core and that he currently views any differences in behavior between Celluloid and Erlang as bugs in Celluloid.

One overarching theme for me of my time at JRubyConf: There is a lot of stuff I don't know. I won't run out of things to read and learn and do for a long, long, time.

~~~~

IMAGE 1: my photo of Sarah Allen during her talk on agile business development. License: Creative Commons Attribution-ShareAlike 3.0 Unported.

IMAGE 2: Jay-Z, 2011. Source: Wikimedia Commons.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

May 28, 2012 10:58 AM

The Spirit of Ruby... and of JRuby

JRubyConf was my first Ruby-specific conference, and one of the things I most enjoyed was seeing how the spirit of the language permeates the projects created by its community of users. It's one thing to read books, papers, and blog posts. It's another to see the eyes and mannerisms of the people using the language to make things they care about. Being a variant, JRuby has its own spirit. Usually it is in sync with Ruby's, but occasionally it diverges.

the letter thnad, created

The first talk after lunch was by Ian Dees, talking about his toy programming language project Thnad. (He took the name from one of the new letters of the alphabet in Dr. Seuss's On Beyond Zebra.) Thnad looks a lot like Klein, a language I created for my compiler course a few years ago, a sort of functional integer assembly language.

The Thnad project is a great example of how easy it is to roll little DSLs using Ruby and other DSLs created in it. To implement Thnad, Dees uses Parslet, a small library for generating scanners and parsers PEG-style, and BiteScript, a Ruby DSL for generating Java bytecode and classes. This talk demonstrated the process of porting Thnad from JRuby to Rubinius, a Ruby implementation written in Ruby. (One of the cool things I learned about the Rubinius compiler is that it can produce s-expressions as output, using the switch -S.)

Two other talks exposed basic tenets of the Ruby philosophy and the ways in which implementations such as JRuby and Rubinius create new value in the ecosystem.

On Wednesday afternoon, David Wood described how his company, the Jun Group, used JRuby to achieve the level of performance its on-line application requires. He told some neat stories about the evolution of on-line media over the last 15-20 years and how our technical understanding for implementing such systems has evolved in tandem. Perhaps his most effective line was this lesson learned along the way, which recalled an idea from the keynote address the previous morning:

Languages don't scale. Architectures do. But language and platform affect architecture.

In particular, after years of chafing, he had finally reached peace with one of the overarching themes of Ruby: optimize for developer ease and enjoyment, rather than performance or scalability. This is true of the language and of most of the tools built around, such as Rails. As a result, Ruby makes it easy to write many apps quickly. Wood stopped fighting the lack of emphasis on performance and scalability when he realized that most apps don't succeed anyway. If one does, you have to rewrite it anyway, so suck it up and do it. You will have benefited from Ruby's speed of delivery.

This is the story Twitter, apparently, and what Wood's team did. They spent three person-months to port their app from MRI to JRuby, and are now quite happy.

Where does some of that performance bump come from? Concurrency. Joe Kutner gave a talk after Thnad on Tuesday afternoon about using JRuby to deploy efficient Ruby web apps on the JVM, in which he also exposed a strand of Ruby philosophy and place where JRuby diverges.

The canonical implementations of Ruby and Python use a Global Interpreter Lock to ensure that non-thread-safe code does not interfere with the code in other threads. In effect, the interpreter maps all threads onto a single thread in the kernel. This may seem like an unnecessary limitation, but it is consistent with Matz's philosophy for Ruby: Programming should be fun and easy. Concurrency is hard, so don't do allow it to interfere with the programmer's experience.

Again, this works just fine for many applications, so it's a reasonable default position for the language. But it does not work so well for web apps, which can't scale if they can't spawn new, independent threads. This is a place where JRuby offers a big win by running atop the JVM, with its support for multithreading. It's also a reason why the Kilim fibers GSoC project mentioned by Charles Nutter in the State of JRuby session is so valuable.

In this talk, I learned about three different approaches to delivering Ruby apps on the JVM:

  • Warbler, a light and simple tool for packaging .war files,
  • Trinidad, which is a JRuby wrapper for a Tomcat server, and
  • TorqueBox, an all-in-one app server that appears to be the hot new thing.

Links, links, and more links!

Talks such as these reminded me of the feeling of ease and power that Ruby gives developers, and the power that language implementors have to shape the landscape in which programmers work. They also gave me a much better appreciation for why projects like Rubinius and JRuby are essential to the Ruby world because -- not despite -- deviating from a core principle of the language.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

May 25, 2012 4:07 PM

JRubyConf, Day 1: The State of JRuby

Immediately after the keynote address, the conference really began for me. As a newcomer to JRuby, this was my first chance to hear lead developers Charles Nutter and Tom Enebo talk about the language and community. The program listed this session as "JRuby: Full of Surprises", and Nutter opened with a slide titled "Something About JRuby", but I just thought of the session as a "state of the language" report.

Nutter opened with some news. First, JRuby 1.7.0.preview1 is available. The most important part of this for me is that Ruby 1.9.3 is now the default language mode for the interpreter. I still run Ruby 1.8.7 on my Macs, because I have never really needed more and that kept my installations simple. It will be nice to have a 1.9.3 interpreter running, too, for cases where I want to try out some of the new goodness that 1.9 offers.

Second, JRuby has been awarded eight Google Summer of Code placements for 2012. This was noteworthy because there were no Ruby projects at all in 2010 or 2011, for different reasons. Several of the 2012 projects are worth paying attention to:

  • creating a code generator for Dalvik byte code, which will give native support for JRuby on Android
  • more work on Ruboto, the current way to run Ruby on Android, via Java
  • implementing JRuby fibers using Kilim fibers, for lighterweight and faster concurrency than Java threads can provide
  • work on krypt, "SSL done right" for Ruby, which will eliminate the existing dependence on OpenSSL
  • filling in some of the gaps in the graphics framework Shoes, both Swing and SWT versions

Charles Nutter discussing details of the JRuby compiler

Enebo then described several projects going on with JRuby. Some are smaller, including closing gaps in the API for embedding Ruby code in Java, and Noridoc, a tool for generating integrated Ruby documentation for Ruby and Java APIs that work together. Clever -- "No ri doc".

One project is major: work on the JRuby compiler itself. This includes improving to the intermediate representation used by JRuby, separating more cleanly the stages of the compiler, and writing a new, better run-time system. I didn't realize until this talk just how much overlap there is in the existing scanner, parser, analyzer, and code generator of JRuby. I plan to study the JRuby compiler in some detail this summer, so this talk whet my appetite. One of the big challenges facing the JRuby team is to identify execution hot spots that will allow the compiler to do a better job of caching, inlining, and optimizing byte codes.

This led naturally into Nutter's discussion of the other major project going on: JRuby support for the JVM's new invokedynamic instruction. He hailed invokedynamic as "the most important change to the JVM -- ever". Without it, JRuby's method invocation logic is opaque to the JVM optimizer, including caching and inlining. With it, the JRuby compiler will be able not only to generate optimizable function calls but also more efficient treatment of instance variables and constants.

Charles Nutter donning his new RedHat

Nutter showed some performance data comparing JRuby to MRI Ruby 1.9.3 on some standard benchmarks. Running on Java 6, JRuby is between 1.3 and 1.9 times faster than the C-based compiler on the benchmark suites. When they run it on Java 7, performance jumps to speed-ups of between 2.6 and 4.3. That kind of speed is enough to make JRuby attractive for many compute-intensive applications.

Just as Nutter opened with news, he closed with news. He and Enebo are moving to RedHat. They will work with various RedHat and JBoss teams, including TorqueBox, which I'll mention in an upcoming JRubyConf post. Nutter and Enebo have been at EngineYard for three years, following a three-year stint at Sun. It is good to know that, as the corporate climate around Java and Ruby evolves, there is usually a company willing to support open-source JRuby development.

~~~~

IMAGE 1: my photo of Charles Nutter talking about some details of the JRuby compiler. License: Creative Commons Attribution-ShareAlike 3.0 Unported.

IMAGE 2: my photo of Charles Nutter and Tom Enebo announcing their move to RedHat. License: Creative Commons Attribution-ShareAlike 3.0 Unported.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

May 24, 2012 3:05 PM

JRubyConf 2012: Keynote Address on Polyglot Programming

JRubyConf opened with a keynote address on polyglot programming by Venkat Subramaniam. JRuby is itself a polyglot platform, serving as a nexus between a highly dynamic scripting language and a popular enterprise language. Java is not simply a language but an ecosphere consisting of language, virtual machine, libraries, and tools. For many programmers, the Java language is the weakest link in its own ecosphere, which is one reason we see so many people porting their favorite languages run on the JVM, or creating new languages with the JVM as a native backend.

Subramaniam began his talk by extolling the overarching benefits of being able to program in many languages. Knowing multiple programming languages changes how we design software in any language. It changes how we think about solutions. Most important, it changes how we perceive the world. This is something that monolingual programmers often do not appreciate. When we know several languages well, we see problems -- and solutions -- differently.

Why learn a new language now, even if you don't need to? So that you can learn a new language more quickly later, when you do need to. Subramaniam claimed that the amount of time required to learn a new language is inversely proportional to the number of languages a person has learned in last ten years. I'm not sure whether there is any empirical evidence to support this claim, but I agree with the sentiment. I'd offer one small refinement: The greatest benefits come from learning different kinds of language. A new language that doesn't stretch your mind won't stretch your mind.

Not everything is heaven for the polyglot programmer. Subramaniam also offered some advice for dealing with the inevitable downsides. Most notable among these was the need to "contend with the enterprise".

Many companies like to standardize on a familiar and well-established technology stack. Introducing a new language into the mix raises questions and creates resistance. Subramaniam suggested that we back up one step before trying to convince our managers to support a polyglot environment and make sure that we have convinced ourselves. If you were really convinced of a language's value, you would find a way to do it. Then, when it comes time to convince your manager, be sure to think about the issue from her perspective. Make sure that your argument speaks to management's concerns. Identify the problem. Explain the proposed solution. Outline the costs of the solution. Outline its benefits. Show how the move can be a net win for the organization.

The nouveau JVM languages begin with a head start over other new technologies because of their interoperability with the rest of the Java ecosphere. They enable you to write programs in a new language or style without having to move anyone else in the organization. You can experiment with new technology while continuing to use the rest of the organization's toolset. If the experiments succeed, managers can have hard evidence about what works well and what doesn't before making larger changes to the development environment.

I can see why Subramaniam is a popular conference speaker. He uses fun language and coins fun terms. When talking about people who are skeptical of unit testing, he referred to some processes as Jesus-driven development. He admonished programmers who are trying to do concurrency in JRuby without knowing the Java memory model, because "If you don't understand the Java memory model, you can't get concurrency right." But he followed that immediately with, Of course, even if you do know the Java memory model, you can't get concurrency right. Finally, my favorite: At one point, he talked about how some Java developers are convinced that they can do anything they need to do in Java, with no other languages. He smiled and said, I admire Java programmers. They share an unrelenting hope.

There were times, though, when I found myself wanting to defend Java. That happens to me a lot when I hear talks like this one, because so many complaints about it are really about OOP practiced poorly; Java is almost an innocent bystander. For example, the speaker chided Java programmers for suffering from primitive obsession. This made me laugh, because most Ruby programmers seem to have an unhealthy predilection for strings, hashes, and integers.

In other cases, Subramaniam demonstrated the virtues of Ruby by showing a program that required a gem and then solved a thorny problem with three lines of code. Um, I could do that in Java, too, if I used the right library. And Ruby programmers probably don't want to draw to much attention to gems and the problems many Ruby devs have with dependency management.

But those are small issues. Over the next two days, I repeatedly heard echoes of Subramaniam's address in the conference's other talks. This is the sign of a successful keynote.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

May 11, 2012 2:31 PM

Get Busy; Time is Short

After an award-winning author had criticized popular literature, Stephen King responded with advice that is a useful reminder to us all:

Get busy. You have a short life span. You need to stop this crap about sitting there and talking about what we do, and actually do it. Because God gave you some talent, but he also gave you a certain number of years.

You don't have to be an award-winning author to waste precious time commenting on other people's work. Anyone with a web browser can fill his or her day talking about stuff, and not actually making stuff. For academics, it is a professional hazard. We need to balance the analytic and the creative. We learn by studying others' work and writing about it, but we also need to make time to make.

(The passage above comes from Stephen King, The Art of Fiction No. 189, in the wonderful on-line archive of interviews from the Paris Review.)


Posted by Eugene Wallingford | Permalink | Categories: General, Software Development

May 10, 2012 12:18 PM

Code Signatures in Lisp

Recently, @fogus tweeted:

I wonder if McCarthy had to deal with complaints of parentheses count in the earliest Lisps?

For me, this tweet immediately brought to mind Ward Cunningham's experiment with file signatures as an aid in browsing unfamiliar code, which he presented at a workshop on "software archeology" at OOPSLA 2001. In his experiment, Ward collapsed each file in the Java 1.3 source code distribution into a single line consisting of only braces, quotes, and semicolons. For example, the AWT class java.awt.peer.ComponentPeer looked like this:

    ;;;;;;;;{;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;} 

while java.awt.print.PageFormat looked like this:

    {;{;;}{;;};}{;;{;}{;};}{;;{;}{;};}{;{;;;;;;"";};}{;{;;;;;;"";};}{;{;}{;};}{;{;}{;};}{}{}{;}{;}{{;}{;}}{;}{;;;;;;}{}{;{;;;;;;;;;;;;;;;;;;;;;;};}}

As Ward said, it takes some time to get use to the "radical summarization" of files into such punctuation signatures. He was curious about how such a high-level view of a code base might help a programmer understand the regularities and irregularities in the code, via an interactive process of inspection and projection.

Perhaps this came to mind as a result of experiences I had when I was first learning to program in Scheme. Coming from other languages with more syntax, I developed a bad habit of writing code like this:

    (define factorial
      (lambda (n)
        (if (zero? n)
            1
            (* n (factorial (- n 1)))
        )))

When real Scheme and Lisp programmers saw my code, they suggested that I put those closing parens at the end of the multiplication line. They were even more insistent when I dropped closing parens onto separate lines in the middle of a larger piece of code, say, with a let expression of several complex values. I objected that the line breaks helped me to see the structure of my code better. They told me to trust them; after I had more experience, I wouldn't need the help, and my code would be cleaner and more idiomatic.

They were right. Eventually, I learned to read Scheme code more like real Schemers do. I found myself drawn to the densest parts of the code, in which those closing parens often played a role, and learned to see that that's where the action usually was.

I think it was the connection between counting parentheses and the structure of code that brought to mind Ward's work. And then I wondered what it would be like to take the signature of Lisp or Scheme code in terms of its maligned primary punctuation, the parentheses?

In a few spare minutes, I fiddled with the I idea. As an example, consider the following Lisp function, which is part of an implementation of CLOS written by Patrick Henry Winston and Berthold Horn to support their AI and Lisp textbooks:

    (defun call-next-method ()
      (if *around-methods*
          (apply (pop *around-methods*) *args*)
        (progn
          (do () ((endp *before-methods*))
            (apply (pop *before-methods*) *args*))
          (multiple-value-prog1
              (if *primary-methods*
	          (apply (pop *primary-methods*) *args*)
                (error "Oops, no applicable primary method!")) 
            (do () ((endp *after-methods*))
              (apply (pop *after-methods*) *args*))))))

Collapsing this function into a single line of parentheses results in:

    (()((())((()(())(()))(((())())(()(())(()))))))

The semicolons in Java code give the reader a sense of the code's length; collapsing Lisp in this way loses the line breaks. So I wrote another function to insert a | where the line breaks had been, which results in:

    (()|(|(())|(|(()(())|(()))|(|(|(())|())|(()(())|(()))))))

This gives a better idea of how the code plays out on the page, but it loses all sense of the code's structure, which is so important when reading Lisp. So I implemented a third signature, one that surrenders the benefit of a single line in exchange for a better sense of structure. This signature preserves leading white space and line breaks but otherwise gives us just the parentheses:

    (()
      (
          (())
        (
          (()(())
          (()))
          (
            (
           (())
               ())
        (()(())
          (()))))))

Interesting. It's almost art.

I think there is a lot of room left to explore here in terms of punctuation. To capture the nature of Scheme and Lisp programs, we would probably want to include other characters, such as the hash, the comma, quotes, and backquotes. These would expose macro-related expressions to the human reader. To expand the experiment to include Clojure, we would of course want to include [] and {} in the signatures.

I'm not an every-day Schemer, so I am not sure how much either the flat signatures or the structured signatures would help seasoned Lisp or Scheme programmers develop an intuitive sense of a function's size, complexity, and patterns. As Ward's experiment showed, the real value comes when signing entire files, and for that task flat signatures may have more appeal. It would be neat to apply this idea to a Lisp distribution of non-trivial size -- say, the full distribution of Racket or Clojure -- and see what might be learned.


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

May 07, 2012 3:21 PM

The University as a Gym for the Mind

In recent years, it is becoming even more common for people to think of students as "paying customers" at the university. People inside of universities, especially the teachers, have long tried to discourage this way of thinking, but it is becoming much harder to make the case. Students and parents are being required to shoulder an ever larger share of the bill for higher education, and with that comes a sense of ownership. Still, educators can't help but worry. The customer isn't always right.

Rob Miles relates a story that might help us make the case:

the gym: a university for the body

You can join a gym to get fit, but just joining doesn't make you fit. It simply gives you access to machinery and expertise that you can use to get fit. If you fail to listen to the trainer or make use of the equipment then you don't get a better body, you just get poorer.

You can buy all the running shoes you like, but if you never lace them up and hit the road, you won't become a runner.

I like this analogy. It also puts into perspective a relatively recent phenomenon, the assertion that software developers may not need a university education. Think about such an assertion in the context of physical fitness:

A lot of people manage to get in shape physically without joining a gym. To do so, all you need is the gumption (1) to learn what they need to do and (2) to develop and stick to a plan. For example, there is a lot of community support among runners, who are willing to help beginners get started. As runners become part of the community, they find opportunities to train in groups, share experiences, and run races together. The result is an informal education as good as most people could get by paying a trainer at a gym.

The internet and the web have provided the technology to support the same sort of informal education in software development. Blogs, user groups, codeathons, and GitHub all offer the novice opportunities to get started, "train" in groups, share experiences, and work together. With some gumption and hard work, a person can become a pretty good developer on his or her own.

But it takes a lot of initiative. Not all people who want to get in shape are ready or able to take control of their own training. A gym serves the useful purpose of getting them started. But each person has to do his or her own hard work.

Likewise, not all learners are ready to manage their own educations and professional development -- especially at age 18, when they come out of a K-12 system that can't always prepare them to be completely independent learners. Like a gym, a university serves the useful purpose of helping such people get started. And just as important, as at the gym, students have to do their own hard work to learn, and to prepare to learn on their own for the rest of their careers.

Of course, other benefits may get lost when students bypass the university. I am still idealistic enough to think that a liberal education, even a liberal arts education, has great value for all people. [ 1 | 2 | 3 ]. We are more than workers in an economic engine. We are human beings with a purpose larger than our earning potentials.

But the economic realities of education these days and the concurrent unbundling of education made possible by technology mean that we will have to deal with issues such as these more and more in the coming years. In any case, perhaps a new analogy might help us help people outside the university understand better the kind of "customer" our students need to be.

(Thanks to Alfred Thompson for the link to Miles's post.)


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

April 30, 2012 4:00 PM

Processing Old Languages and Thinking of New

I'm beginning to look at the compilers my students produced this semester. I teach a relatively traditional compiler course; we want students to experience as many different important ideas as possible within the time constraints of a semester. As you might expect, my students' programs read in a text file and produce a text file. These files contain a high-level program and an assembly language program, respectively.

I love seeing all the buzz floating around non-textual languages and new kinds of programming environments such as Bret Victor's reactive documents and Light Table. Languages and environments like these make my traditional compiler course seem positively archaic. I still think the traditional course adds a lot of value to students' experience. Before you can think outside of the box, you have to start with a box.

These new programming ideas really are outside the confines of how we think about programs. Jonathan Edwards reminds us how tightly related languages and tools are:

As long as we are programming in descendants of assembly language, we will continue to program in descendants of text editors.

Edwards has been exploring this pool of ideas for a few years now. I first mentioned his work in this blog back in 2004. As he has learned, the challenge we face in trying to re-think how we program is complicated by the network of ideas in which we work. It isn't just syntax or language or IDE or support tools that we have to change. To change one in a fundamental way requires changing them all.

On top of that, once researchers create something new, we will have to find a way to migrate there. That involves education and lots of existing practitioners. Here's hoping that the small steps people are taking with Tangle and Light Table can help us bridge the gap.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

March 18, 2012 5:20 PM

Thinking Out Loud about the Compiler in a Pure OO World

John Cook pokes fun at OO practice in his blog post today. The "Obviously a vast improvement." comment deftly ignores the potential source of OOP's benefits, but then that's the key to the joke.

A commenter points to a blog entry by Smalltalk veteran Travis Griggs. I agree with Griggs's recommendation to avoid using verbs-turned-into-nouns as objects, especially lame placeholder words such as "manager" and "loader". As he says, they usually denote objects that fiddle with the private parts of other objects. Those other objects should be providing the services we need.

Griggs allows reasonable linguistic exceptions to the advice. But he also acknowledges the pull of pop culture which, given my teaching assignment this semester, jumped out at me:

There are many 'er' words that despite their focus on what they do, have become so commonplace, that we're best to just stick with them, at least in part. Parser. Compiler. Browser.

I've thought about this break in my own OO discipline before, and now I'm thinking about it again. What would it be like to write compiles without creating parsers and code generators -- and compilers themselves -- as objects?

We could ask a program to compile itself:

     program.compileTo( targetMachine )
But is the program a program, or does it start life as a text file? If the program starts as a text file, perhaps we say
  program.parse()
to create an abstract syntax tree, which we then could ask
  ast.compileTo( targetMachine )

(Instead of sending a parse() message, we might send an asAbstractSyntax() message. There may be no functional difference, but I think the two names indicate subtle differences in mindset.)

When my students write their compilers in Java or another OO language, we discuss in class whether abstract syntax trees ought to be able to generate target code for themselves. The danger lies in binding the AST class to the details of a specific target machine. We can separate the details of the target machine for the AST by passing an argument with the compileTo() message, but what?

Given all the other things we have to learn in the course, my students usually end up following Griggs's advice and doing the traditional thing: pass the AST as an argument to a CodeGenerator object. If we had more time, or a more intensive OO design course prior to the compilers course, we could look at techniques that enable a more OO approach without making things worse in the process.

Looking back farther to the parse behavior, would it ever make sense to send an argument with the parse() message? Perhaps a parse table for an LL(1) or LR(1) algorithm? Or the parsing algorithm itself, as a strategy object? We quickly run the risk of taking steps in the direction that Cook joshes about in his post.

Or perhaps parsing is a natural result of creating a Program object from a piece of text. In that approach, when we say

     Program source = new Program( textfile );
the internal state of source is an abstract syntax tree. This may sound strange at first, but a program isn't really a piece of text. It's just that we are conditioned to think that way by the languages and tools most of us learn first and use most heavily. Smalltalk taught us long ago that this viewpoint is not necessary. (Lisp, too, though in a different way.)

These are just some disconnected thoughts on a Sunday afternoon. There is plenty more to say, and plenty of prior art. I think I'll fire up a Squeak image sometime soon and spend some time reacquainting myself with its take on parsing and code generation, in particular the way it compiles its core out to C.

I like doing this kind of "what if?" thinking. It's fun to explore along the boundary between the land where OOP works naturally and the murky territory where it doesn't seem to fit so well. That's a great place to learn new stuff.


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

March 13, 2012 8:00 PM

The Writer's Mindset for Programmers

Several people have pointed out that these tips on writing from John Steinbeck are useful for programmers; Chris Freeman even mapped them to writing code. I like to make such connections, most recently to the work of Roger Rosenblatt (in several entries, including The Summer Smalltalk Taught Me OOP) and John McPhee, a master of non-fiction (in an entry on writing, teaching, and programming). Lately I have been reading about and from David Foster Wallace, as I wrote a few weeks ago. Several quotes from interviews he gave in the 1990s and 2000s reminded me of programming, both doing it and learning to do it.

The first ties directly into the theme from the entry on my summer of Smalltalk. As Wallace became more adept at making the extensive cuts to his wide-ranging stories suggested by his editor, he adopted a familiar habit:

Eventually, he learned to erase passages that he liked from his hard drive, in order to keep himself from putting them back in.

It's one thing to kill your darlings. It's another altogether to keep them from sneaking back in. In writing as in programming, sometimes rm -r *.* is your friend.

A major theme in Wallace's work -- and life -- was the struggle not to fall into the comfortable patterns of thought engendered by the culture around us. The danger is, those comfortable ruts separate us from what is real:

Most 'familiarity' is mediated and delusive.

Programmers need to keep this in mind when they set out to learn a new programming language and or a new style of programming. We tend to prefer the familiar, whether it is syntax or programming model. Yet familiarity is conditioned by so many things, most prominently recent experience. It deludes us into thinking some things are easier or better than others, often for no other reason than the accident of history that brought us to a particular language or style first. When we look past the experience that gets in the way of seeing the new thing as it is, we enable ourselves to appreciate the new thing as it is, and not as the lens of our experience distorts it.

Of course, that's easier said than done. This struggle consumed Wallace the writer his entire life.

Even so, we don't want to make the mistake of floating along the surface of language and style. Sometimes, we think that makes us free to explore all ideas unencumbered by commitment to any particular syntax, programming model, or development methodology. But it is in focusing our energies and thinking to use specific tools, to write in a specific cadre of languages, and to use a particular styles that we enable ourselves to create, to do something useful:

If I wanted to matter -- even just to myself -- I would have to be less free, by deciding to choose in some kind of definite way.

This line is a climactic revelation of the protagonist in Wallace's posthumously published unfinished novel, The Pale King. It reminds us that freedom is not always so free.

It is much more important for a programmer to be a serial monogamist than a confirmed bachelor. Digging deep into language and style is what makes us stronger, whatever language or style we happen to work in at any point in time. Letting comfortable familiarity mediate our future experiences is simply a way of enslaving ourselves to the past.

In the end, reading Wallace's work and the interviews he gave shows us again that writers and programmers have a lot in common. Even after we throw away all the analogies between our practices, processes, and goals, we are left with an essential identity that we programmers share with our fellow writers:

Writing fiction takes me out of time. That's probably as close to immortal as we'll ever get.

Wallace said this in the first interview he gave after the publication of his first novel. It is a feeling I know well, and one I never want to live without.


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

February 19, 2012 12:17 PM

The Polymorphism Challenge

Back at SIGCSE 2005, Joe Bergin and ran a workshop called The Polymorphism Challenge that I mentioned at the time but never elaborated on. It's been on my mind again for the last week. First I saw a link to an OOP challenge aimed at helping programmers move toward OO's ideal of small classes and short methods. Then Kent Beck tweeted about the Anti-IF Campaign, which, as its name suggests, wants to help programmers "avoid dangerous ifs and use objects to build a code that is flexible, changeable, and easily testable".

That was the goal of The Polymorphism Challenge. I decided it was time to write up the challenge and make our workshop materials available to everyone.

Background

Beginning in the mid-1990s, Joe and I have been part of a cabal of CS educators trying to teach object-oriented programming style better. We saw dynamic polymorphism as one of the key advantages to be found in OOP. Getting procedural programmers to embrace it, including many university instructors, was a big challenge.

At ChiliPLoP 2003, our group was riffing on the idea of extreme refactoring, during which Joe and I created a couple of contrived examples eliminating if statements from a specific part of Karel the Robot that seemed to require them.

This led Joe to propose a programming exercise he called an étude, similar to what these days are called katas, which I summarized in Practice for Practice's Sake:

Write a particular program with a budget of n if-statements or fewer, for some small value of n. Forcing oneself to not use an if statement wherever it feels comfortable forces the programmer to confront how choices can be made at run-time, and how polymorphism in the program can do the job. The goal isn't necessarily to create an application to keep and use. Indeed, if n is small enough and the task challenging enough, the resulting program may well be stilted beyond all maintainability. But in writing it the programmer may learn something about polymorphism and when it should be used.

Motivated by the Three Bears pattern, Joe and I went a step further. Perhaps the best way to know that you don't need if-statements everywhere is not to use them anywhere. Turn the dials to 11 and make 'em all go away! Thus was born the challenge, as a workshop for CS educators at SIGCSE 2005. We think it is useful for all programmers. Below are the materials we used to run the workshop, with only light editing.

Task

Working in pairs, you will write (or re-write) simple but complete programs that normally use if statements, to completely remove all selection structures in favor of polymorphism.

Objective

The purpose of this exercise is not to demonstrate that if statements are bad, but that they aren't necessary. Once you can program effectively this way, you have a better perspective from which to choose the right tool. It is directed at skilled procedural programmers, not at novices.

Rules

You should attempt to build the solutions to one of the challenge problems without using if statements or the equivalent.

You may use the libraries arbitrarily, even when you are pretty sure that they are implemented with if statements.

You may use exceptions only when really needed and not as a substitute for if statements. Similarly, while loops are not to be used to simulate if statements. Your problems should be solved with polymorphism: dynamic and parameterized.

Note that if you use (for example) a hash map and the program cannot control what is used as a key in a get (user input, for example). then it might return null. You are allowed to use an exception to handle this situation, or even an if. If you can't get all if statements out of your code, then see how few you really need to live with.

Challenges

Participants worked in pairs. They had a choice of programming scenarios, some of which were adapted from work by others:

This pdf file contains the full descriptions given to participants, including some we did not try with workshop participants. If you come up with a good scenario for this challenge, or variations on ours, please let me know.

Hints

When participants hit a block and asked for pointers, we offered hints of various kinds, such as:

•  When you have two behaviors, put them into different objects. The objects can be created from the same class or from related classes. If they are from the same class, you may want to use parameterized polymorphism. When the classes are different, you can use dynamic polymorphism. This is the easy step. Java interfaces are your friend here.

•  When you have the behaviors in different objects, find a way to bring the right object into play at the right time. That way, you don't need to use ad hoc methods to distinguish among them. This is the hard part. Sometimes you can develop a state change diagram that makes it easier. Then you can replace one object with another at the well-defined state change points.

•  Note that you can eliminate a lot of if statements by capturing early decisions -- perhaps made using if statements -- in different objects. These objects can then act as "flags with behavior" when they are passed around the program. The flag object then encapsulates the earlier decision. Now try to capture those decisions without if statements.

(Note that this technique alone is a big win in improving the maintainability of code. You replace many if statements spread throughout a program with one, giving you a single point of change in future.)

•  Delegation from one object to another is a real help in this exercise. This leads you to the Strategy design pattern. An object M can carry with it another, S, that encapsulates the strategy M has for solving a problem. To perform the associated behavior, M delegates to S. By changing the strategy object, you can change the behavior of the object that carries it. M seems to behave polymorphically, but it is really S that does the work.

•  You can modify or enhance strategies using the Decorator design pattern. A decorator D implements the same interface as the thing it decorates, M. When sent a message, the decorator performs some action and also sends the same message to the object it decorates. Thus the behavior of M is executed, but also more. Note that D can provide additional functionality both before and after sending the message to M. A functional method can return quite a different result when sent through a decorated object.

•  You can often choose strategies or other objects that encapsulate decisions using the Factory design pattern. A hash map can be a simple factory.

•  You can sometimes use max and min to map a range of values onto a smaller set and then use an index into a collection to choose an object. max and min are library functions so we don't care here how they might be implemented.

At the end of the workshop, we gave one piece of general advice: Doing this exercise once is not enough. Like an étude, it can be practiced often, in order to develop and internalize the necessary skills and thought patterns.

Conclusion

I'll not give any answers or examples here, so that readers can take the challenge themselves and try their hand at writing code. In future posts, I'll write up examples of the techniques described in the hints, and perhaps a few others.

Joe wrote up his étude in Variations on a Polymorphic Theme. In it, he gives some advice and a short example.

Serge Demeyer, Stéphane Ducasse, and Oscar Nierstrasz wrote a wonderful paper that places if statements in the larger context of an OO system, Transform Conditionals: a Reengineering Pattern Language.

If you like the Polymorphism Challenge, you might want to try some other challenges that ask you to do without features of your preferred language or programming style that you consider essential. Check out these Programming Challenges.

Remember, constraints help us grow. Constraints are where creative solutions happen.

I'll close with the same advice we gave at the end of the workshop: Doing this exercise once is not enough, especially for OO novices. Practice it often, like an étude or kata. Repetition can help you develop the thought patterns of an OO programmer, internalize them, and build the skills you need to write good OO programs.


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

February 15, 2012 4:41 PM

Architecture Without Architects

David Byrne's essay on collective-creation introduced me to a dandy little picture book by Bernard Rudofsky called Architecture Without Architects. I love a slim book, and I love architecture, so I didn't need much of a push to pick it up at the library.

For an agile software developer, the book's title evokes something visceral. I think software architecture often happens best when it happens organically, emerging as the programmer grows the program piecemeal, feature by feature. This is a pragmatic view, as expressed succinctly by Brian Marick in his recent The Aim of Architecture:

Architecture isn't true, it's useful.

In software, as Marick says, knowing a program's architecture helps us to navigate our way around the program and add new code. An agile developer is willing to let architecture describe the existing program, rather than prescribe its shape. A descriptive, emergent architecture will be more helpful in what we need it for than a prescribed, often inaccurate architecture created ahead of time.

That's the mindset I brought to Architecture Without Architects. I found, though, that it is about more than piecemeal growth and emergence; it talks about buildings and spaces created by regular people. Some people call this "vernacular" architecture, but Rudofsky uses a number of terms aimed at elevating the idea beyond the vulgar, among them "indigenous", "spontaneous", and "non-pedigreed". I think Rudofsky likes "non-pedigreed" best because it most accurately expresses the distinction between the creations he studies and "real" architecture: the only difference is the credential held by the builder.

He lays responsibility for this harmful distinction at the feat of historians, who emphasize "the parts played by architects and their patrons" at the expense of "the communal enterprise" of the built environment. But all of us share in the blame:

Part of our trouble results from the tendency to ascribe to architects -- or, for that matter, to all specialists -- exceptional insights into problems of living when, in truth, most of them are concerned with problems of business and prestige.

One of the goals of this book is to encourage the study of non-pedigreed architecture, to describe a typology and to document important examples. "There is much to learn," says Rudofsky, "from architecture before it became an expert's art".

So, it turns out that Architecture Without Architects is not about the same sense of "without architect" that we in the software world usually mean. Agile developers are, for the most part, professionals, not hobbyists or regular Joes cobbling together programs on the side. Part of that is cultural. People who would never think of writing a program for themselves think nothing about diddling around their houses. Part of it is technological. It's pretty easy to go to the nearest home improvement center and buy modular components that non-professionals can use to change the shape and decoration of their houses. Programming, not so much.

There are, of course, a few hobbyists tinkering around with programs in their spare time. More important, there are plenty of people with few or no credentials in computing or software engineering making a living by writing programs. Sometimes, they have switched careers out of necessity or choice. Other times, they have slowly drifted into software development over the course of a career.

In yet other cases, they retain their professional identity in another discipline and write code to help them do their jobs. Greg Wilson's Software Carpentry project is aimed at one such group of people: professional scientists who find themselves writing and maintaining software as an essential part of doing their science. Rudofsky may be right when he chides us for attributing exceptional insight to professional architects, and if so we are certainly right not to attribute exceptional insight to pedigreed software developers. But Wilson is building a brand by reminding us that, while it may not take exceptional insight to write programs, doing it well does require some skill and knowledge.

I think that Rudofsky's interest in vernacular architecture has other parallels in the software world. For example, technologies such as SourceForge and now GitHub have enabled developers to showcase, celebrate, and benefit from the communal enterprise of writing programs. Programmers may be sitting home working on their own, but they aren't really alone. They are sharing what they write, sharing in what others write, and otherwise participating in vibrant communities of developers.

Then there is the idea of credentials. While many programmers do have degrees in computer science or engineering, most professionals don't have advanced academic degrees or an academic bent. They write code in a world shaped by forces beyond those usually talked about in algorithms and data structures textbooks. The software patterns movement that grew up in the 1990s aimed to document valuable lessons learned programming "in the wild". Like Rudofsky's typology of indigenous architecture, catalogs of design patterns collected vernacular wisdom. As Rudofsky said about the creations of the anonymous builders of most of the world we actually live in,

The beauty of this architecture has long been dismissed as accidental, but today we should be able to recognize it as the result of rare good sense in the handling of practical problems.

Say whatever else you want about the Gang of Four book, it captured a lot of OO wisdom learned in the trenches, often from working with unforgiving building materials like C++.

I enjoyed Architecture Without Architects greatly. After an eight-page preface in which Rudofsky lays down most of the ideas I've summarized here, the book consists of 150 or so pages of pictures accompanied by explanatory paragraphs. There was a lot of interesting detail and even a little wisdom in those paragraphs. If you like architecture, whether housing or programming, you might enjoy spending a couple of hours with this book.


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

February 08, 2012 11:15 AM

Refactoring as Curve Fitting

Nathan Marz has written a nice article on what he calls suffering-oriented programming, a development style that places great value on "You Aren't Gonna Need It". It also has a guideline for when you should build something: you feel the pain of not having it. If it doesn't hurt yet, then you don't need it.

As you might imagine, Marz reports that the most important characteristic of this style is a relentless focus on refactoring. In refactoring, we often speak of code smells. Suffering-oriented programmers operate within a different metaphor. They are waiting for their code to make their lives difficult, such as when the queues and workers in Marz's stream processing system became unworkable at a larger scale. We need someone like Kent Beck to coin a catchy phrase for this -- code owies, perhaps.

I enjoyed the analogy Marz uses between refactoring and curve fitting:

"Making it beautiful" is where you use your design and abstraction skills to distill the problem space into simple abstractions that can be composed together. I view the development of beautiful abstractions as similar to statistical regression: you have a set of points on a graph (your use cases) and you're looking for the simplest curve that fits those points (a set of abstractions).

Do the simplest thing that would possibly work.

Marz presents a very practical instantiation of agile development without the hype that accompanies some usages of the term. It is worth a read.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

February 01, 2012 5:00 PM

"You Cannot Trust Your Creativity Yet"

You've got to learn your instrument.
Then, you practice, practice, practice.
And then, when you finally get up there on the bandstand,
forget all that and just wail. -- Charlie Parker

I signed up for an opportunity to read early releases of a book in progress, Bootstrapping Design. Chapter 4 contain a short passage that applies to beginning programmers, too:

Getting good at design means cultivating your taste. Right now, you don't have it. Eventually you will, but until then you cannot trust your creativity. Instead, focus on simplicity, clarity, and the cold, hard science of what works.

M.C. Escher, 'Hands'

This is hard advice for people to follow. We like to use our brains, to create, to try out what we know. I see this desire in many beginning programming students. The danger grows as our skills grow. One of my greatest frustrations comes in my Programming Languages course. Many students in the course are reluctant to use straightforward design patterns such as mutual recursion.

At one level, I understand their mindset. They have started to become accomplished programmers in other languages, and they want to think, design, and program for themselves. Oftentimes, their ill-formed approaches work okay in the small, even if the code makes the prof cringe. As our programs grow, though, the disorder snowballs. Pretty soon, the code is out of the student's control. The prof's, too.

A good example of this phenomenon, in both its positive and negative forms, happened toward the end of last semester's course. A series of homework assignments had the students growing an interpreter for a small, Scheme-like language. It eventually became the largest functional program they had ever written. In the end. there was a big difference between code written by students who relied on "the cold, hard science" we covered in class and code written by students who had wondered off into the wilderness of their own creativity. Filled with common patterns, the former was relatively easy to read, search, and grade. The latter... not so much. Even some very strong students began to struggle with their own code. They had relied too much on their own approaches for decomposing the problem and organizing their programs, but those ideas weren't scaling well.

I think what happens is that, over time, small errors, missteps, and complexities accumulate. It's almost like the effect of rounding error when working with floating point numbers. I vividly remember experiencing that in mu undergrad Numerical Analysis courses. Sadly, few of our CS students these days take Numerical Analysis, so their understanding of the danger is mostly theoretical.

Perhaps the most interesting embodiment of trusting one's own creativity too much occurred on the final assignment of the term. After several weeks and several assignments, we had a decent sized program. Before assigning the last set of requirements, I gave everyone in the class a working solution that I had written, for reference. One student was having so much trouble getting his own program to work correctly, even with reference to my code, that he decided to use my code as the basis for his assignment.

Imagine my surprise when I saw his submission. He used my code, but he did not follow the example. The code he added to handle the new requirements didn't look anything like mine, or like what we had studied in class. It repeated many of the choices that had gotten him into hot water over the course of the earlier assignments. I could not help but chuckle. At least he is persistent.

It can be hard to trust new ideas, especially when we don't understand them fully yet. I know that. I do the same thing sometimes. We feel constrained by someone else's programming patterns and want to find our own way. But those patterns aren't just constraints; they are also a source of freedom. I try to let my students grow in freedom as they progress through the curriculum, but sometimes we encounter something new like functional programming and have to step back into the role of uncultivated programmer and grow again.

There is great value in learning the rules first and letting our tastes and design skill evolve slowly. Seniors taking project courses are ready, so we turn them loose to apply their own taste and creativity on Big Problems. Freshmen usually are not yet able to trust their own creativity. They need to take it slow.

To "think outside the box", you you have to start with a box. That is true of taste and creativity as much as it is of knowledge and skill.


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

January 25, 2012 3:45 PM

Pragmatism and the Scientific Spirit

the philosopher William James

Last week, I found myself reading The Most Entertaining Philosopher, about William James. It was good fun. I have always liked James. I liked the work of his colleagues in pragmatism, C.S. Peirce and John Dewey, too, but I always liked James more. For all the weaknesses of his formulation of pragmatism, he always seemed so much more human to me than Peirce, who did the heavy theoretical lifting to create pragmatism as a formal philosophy. And he always seemed a lot more fun than Dewey.

I wrote an entry a few years ago called The Academic Future of Agile Methods, which described the connection between pragmatism and my earlier AI, as well as agile software development. I still consider myself a pragmatist, though it's tough to explain just what that means. The pragmatic stance is too often confounded with a self-serving view of the world, a "whatever works is true" philosophy. Whatever works... for me. James's references to the "cash value" of truth didn't help. (James himself tried to undo the phrase's ill effects, but it has stuck. Even in the 1800s, it seems, a good sound bite was better than the truth.)

As John Banville, the author NY Times book review piece says, "It is far easier to act in the spirit of pragmatism than to describe what it is." He then gives "perhaps the most concise and elegant definition" of pragmatism, by philosopher C. I. Lewis. It is a definition that captures the spirit of pragmatism as well as any few lines can:

Pragmatism could be characterized as the doctrine that all problems are at bottom problems of conduct, that all judgments are, implicitly, judgments of value, and that, as there can be ultimately no valid distinction of theoretical and practical, so there can be no final separation of questions of truth of any kind from questions of the justifiable ends of action.

This is what drew me to pragmatism while doing work in knowledge-based systems, as a reaction to the prevailing view of logical AI that seemed based in idealist and realist epistemologies. It is also what seems to me to distinguish agile approaches to software development from the more common views of software engineering. I applaud people who are trying to create an overarching model for software development, a capital-t Theory, but I'm skeptical. The agile mindset is, or at least can be, pragmatic. I view software development in much the way James viewed consciousness: "not a thing or a place, but a process".

As I read again about James and his approach, I remember my first encounters with pragmatism and thinking: Pragmatism is science; other forms of epistemology are mathematics.


Posted by Eugene Wallingford | Permalink | Categories: General, Software Development

January 19, 2012 4:23 PM

An Adventure in Knowing Too Much ... Or Thinking Too Little

To be honest, it is a little of both.

I gave the students in my compilers course a small homework assignment. It's a relatively simple translation problem whose primary goals are to help students refresh their programming skills in their language of choice and to think about the issues we will be studying in depth in coming weeks: scanning, parsing, validating, and generating.

I sat down the other day to write a solution ... and promptly made a mess.

In retrospect, my problem was that I was somewhere in between "do it 'simple'" and "do it 'right'". Unlike most of the students in the class, already know a lot about building compilers. I could use all that knowledge and build a multi-stage processor that converts a string in the source language (a simple template language) into a string in the target language (ASCII text). But writing a scanner, a parser, a static analyzer, and a text generator seems like overkill for such a simple problem. Besides, my students aren't likely to write such a solution, which would make my experience less valuable helping them to solve the problem, and my program less valuable as an example of a reasonable solution.

So I decided to keep things simple. Unfortunately, though, I didn't follow my own agile advice and do the simplest thing that could possibly work. As if with the full-compiler option, I don't really want the simplest program that could possibly work. This problem is simple enough to solve with a single pass algorithm, processing the input stream at the level of individual characters. That approach would work but would obscure the issues we are exploring in the course in a lot of low-level code managing states and conditions. Our goal for the assignment is understanding, not efficiency or language hackery.

I was frustrated with myself, so I walked away.

Later in the day, I was diddling around the house and occasionally mulling over my situation. Suddenly I saw a solution in mind. It embodied a simple understanding of my the problem, in the middle ground between too simple and too complex that was just right.

I had written my original code in a test-first way, but that didn't help me avoid my mess. I know that pair programming would have. My partner would surely have seen through the complexity I was spewing to the fact that I was off track and said, "Huh? Cut that out." Pair programming is an unsung hero in cases like this.

I wonder if this pitfall is a particular risk for CS academics. We teach courses that are full of details, with the goal of helping students understand the full depth of a domain. We often write quick and dirty code for our own purposes. These are at opposite ends of the software development spectrum. In the end, we have to help students learn to think somewhere in the middle. So, we try to show students well-designed solutions that are simple enough, but no simpler. That's a much more challenging task that writing a program at either extreme. Not being full-time developers, perhaps our instincts for finding the happy medium aren't as sharp as they might be.

As always, though, I had fun writing code.


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

December 19, 2011 4:49 PM

"I Love The Stuff You Never See"

I occasionally read and hear people give advice about how to find a career, vocation, or avocation that someone will enjoy and succeed in. There is a lot of talk about passion, which is understandable. Surely, we will enjoy things we are passionate about, and perhaps then we want to put in the hours required to succeed. Still, "finding your passion" seems a little abstract, especially for someone who is struggling to find one.

This weekend, I read A Man, A Ball, A Hoop, A Bench (and an Alleged Thread)... Teller!. It's a story about the magician Teller, one half of the wonderful team Penn & Teller, and his years-long pursuit of a particular illusion. While discussing his work habits, Teller said something deceptively simple:

I love the stuff you never see.

I knew immediately just what he meant.

I can say this about teaching. I love the hours spent creating examples, writing sample code, improving it, writing and rewriting lecture notes, and creating and solving homework assignments. When a course doesn't go as I had planned, I like figuring out why and trying to fix it. Students see the finished product, not the hours spent creating it. I enjoy both.

I don't necessarily enjoy all of the behind-the-scenes work. I don't really enjoy grading. But my enjoyment of the preparation and my enjoyment of the class itself -- the teaching equivalent of "the performance" -- carries me through.

I can also say the same thing about programming. I love to fiddle with source code, organizing and rewriting it until it's all just so. I love to factor out repetition and discover abstractions. I enjoy tweaking interfaces, both the interfaces inside my code and the interfaces my code's users see. I love that sudden moment of pleasure when a program runs for the first time. Users see the finished product, not the hours spent creating it. I enjoy both.

Again, I don't necessarily enjoy everything that I have to do the behind the scenes. I don't enjoy twiddling with configuration files, especially at the interface to the OS. Unlike many of my friends, I don't always enjoy installing and uninstalling, all the libraries I need to make everything work in the current version of the OS and interpreter. But that time seems small compared the time I spend living inside the code, and that carries me through.

In many ways, I think that Teller's simple declaration is a much better predictor of what you will enjoy in a career or avocation than other, fancier advice you'll receive. If you love the stuff other folks never see, you are probably doing the right thing for you.


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

December 15, 2011 4:08 PM

Learning More Than What Is Helpful Right Now

Stanley Fish wrote this week about the end of a course he taught this semester, on "law, liberalism and religion". In this course, his students a number of essays and articles outside the usual legal literature, including works by Locke, Rawls, Hobbes, Kant, and Rorty. Fish uses this essay to respond to recent criticisms that law schools teach too many courses like this, which are not helpful to most students, who will, by and large, graduate to practice the law.

Most anyone who teaches in a university hears criticisms of this sort now and then. When you teach computer science, you hear them frequently. Most of our students graduate and enter practice the software development. How useful are the theory of computation and the principles of programming languages? Teach 'em Java Enterprise Edition and Eclipse and XSLT and Rails.

My recent entry Impractical Programming, With Benefits starts from the same basic premise that Fish starts from: There is more to know about the tools and methodologies we use in practice than meets the eye. Understanding why something is as it is, and knowing that something could be better, are valuable parts of a professional's preparation for the world.

Fish talks about these values in terms of the "purposive" nature of the enterprise in which we practice. You want to be able to thing about the bigger picture, because that determines where you are going and why you are going there. I like his connection to Searle's speech acts and how they help us to see how the story we tell gives rise to the meaning of the details in the story. He uses football as his example, but he could have used computer science.

He sums up his argument in this way

That understanding is what law schools offer (among other things). Law schools ask and answer the question, "What's the game here?"; the ins and outs of the game you learn later, as in any profession. The complaint ... is that law firms must teach their new hires tricks of the trade they never learned in their contracts, torts and (God forbid) jurisprudence classes. But learning the tricks would not amount to much and might well be impossible for someone who did not know -- in a deep sense of know -- what the trade is and why it is important to practice it.

Such a deep understanding is even more important in a discipline like computing, because our practices evolve at a much faster rate than legal practices. Our tools change even more frequently. When we taught functional programming ten or fifteen years ago, many of our students simply humored me. This wasn't going to help them with Windows programming, but, hey, they'd learn it for our sake. Now they live in a world where Scala, Clojure, and F# are in the vanguard. I hope what they learned in our Programming Languages course has helped them cope with the change. Some of them are even leading the charge.

The practical test of whether my Programming Languages students learned anything useful this semester will come not next year, but ten or fifteen years down the road. And, as I said in the Impractical Programming piece, a little whimsy can be fun in its own right, easy while it stretches your brain.


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

December 08, 2011 4:23 PM

Quick and Wrong and Fast and Slow

I've been reading a lot about Daniel Kahneman's new book, Thinking, Fast and Slow. One of the themes of the book is how our brains include two independent systems for organizing and accessing knowledge. System One is incredibly fast but occasionally (perhaps often) wrong. It likely developed early in our biological history and provided humans with an adaptive advantage in a dangerous world. System Two developed later, after humans had survived to create more protective surroundings. It is slow -- conscious, deliberative -- and more often right.

One reviewer summarized the adaptive value of System One in this way:

In the world of the jungle, it is safer to be wrong and quick than to be right and slow.

This phrase reminded me of an old post by Allan Kelly, on the topic of gathering requirements for software. The entry's title is also its punch line:

You are better off being generally right than precisely wrong.

These two quotes are quite different in important ways. Yet they are related in some interesting ways, too.

It is easier to be fast and generally right than to be fast and precisely right. The pattern-matching mechanism in our brains and the heuristics we use consciously are fast, but they are often imprecise. If generally right is good enough, then fast is possible.

Attempts to be slow and precisely right often end up being slow and precisely wrong. Sometimes, the world changes while we are thinking. Other times, we end up solving the wrong problem because we didn't understand our goals or the conditions of the world as well we thought we did at the outset.

Evolution has given us two mechanisms with radically different trade-offs and, it turns out, a biological bias toward quick and wrong.

When I talk with friends who dislike or don't understand agile approaches, I find that they often think that agile folks overemphasize the use of System One in software development. Why react, be wrong, and learn from the mistake, when we could just think ahead and do it right the first time?

In one way, they are right. Some proponents of agile approaches speak rather loosely about Big Design Up Front and about You Aren't Gonna Need It. They leave the impression that one can program without thinking, so long as one takes small enough steps and learns from feedback. They also leave the impression that everyone should work this way, in all contexts. Neither of these impressions is accurate.

I try to help my skeptical friends to understand how a "quick and (sometimes) wrong" mindset can be useful for me even in contexts where I could conceivably plan ahead well and farther. I try to help them understand that I really am thinking all the time I'm working, but that I treat any products of thought that are not yet in code as contingent, awaiting the support of evidence gained through running code.

And then I let them work in whatever way makes them successful and comfortable.

I think that being aware of the presence of Systems One and Two, and the fundamental trade-off between them, can help agile developers work better. Making conscious, well-founded decisions about how far to think ahead, about what and how much to test, and about when and how often to refactor are, in the end, choices about which part of our brain to use at any given moment. Context matters. Experience matters. Blindly working in a quick-and-generally-right way is no more productive approach for most of us than working in a slow-and-sometimes-precisely-wrong way.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

December 02, 2011 4:28 PM

Impractical Programming, with Benefits

I linked to Jacob Harris's recent In Praise of Impractical Programming in my previous entry, in the context of programming's integral role in the modern newsroom. But as the title of his article indicates, it's not really about the gritty details of publishing a modern web site. Harris rhapsodizes about wizards and the magic of programming, and about a language that is for many of my colleagues the poster child for impractical programming languages, Scheme.

If you clicked through to the article but stopped reading when you ran into MIT 6.001, you might want to go back and finish reading. It is a story of how one programmer looks back on college courses that seemed impractical at the time but that, in hindsight, made him a better programmer.

There is a tension in any undergraduate CS program between the skills and languages of today and big ideas that will last. Students naturally tend to prefer the former, as they are relevant now. Many professors -- though not all -- prefer academic concepts and historical languages. I encounter this tension every time I teach Programming Languages and think, should I continue to use Scheme as the course's primary language?

As recently as the 1990s, this question didn't amount to much. There weren't any functional programming languages at the forefront of industry, and languages such as C++, Java, and Ada didn't offer the course much.

But now there are Scala and Clojure and F#, all languages in play in industry, not too mention several "pretty good Lisps". Wouldn't my students benefit from the extensive libraries of these languages? Their web-readiness? The communities connecting the languages to Hadoop and databases and data analytics?

I seriously consider these questions each time I prep the course, but I keep returning to Scheme. Ironically, one reason is precisely that it doesn't have all those things. As Harris learned,

Because Scheme's core syntax is remarkably impoverished, the student is constantly pulling herself up by her bootstraps, building more advanced structures off simpler constructs.

In a course on the principles of programming languages, small is a virtue. We have to build most of what we want to talk about. And there is nothing quite so stark as looking at half a page of code and realizing, "OMG, that's what object-oriented programming is!", or "You mean that's all a variable reference is?" Strange as it may sound, the best way to learn deeply the big concepts of language may be to look at the smallest atoms you can find -- or build them yourself.

Harris "won't argue that "journalism schools should squander ... dearly-won computer-science credits on whimsical introductions to programming" such as this. I won't even argue that we in CS spend too many of our limited credits on whimsy. But we shouldn't renounce our magic altogether, either, for perfectly practical reasons of learning.

And let's not downplay too much the joy of whimsy itself. Students have their entire careers to muck around in a swamp of XML and REST and Linux device drivers, if that's what they desire. There's something pretty cool about watching Dr. Racket spew, in a matter of a second or two, twenty-five lines of digits as the value of a trivial computation.

As Harris says,

... if you want to advance as a programmer, you need to take some impractical detours.

He closes with a few suggestions, none of which lapse into the sort of navel-gazing and academic irrelevance that articles like this one sometimes do. They all come down to having fun and growing along the way. I second his advice.


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

November 30, 2011 7:07 PM

A Definition of Design from Charles Eames

Paul Rand's logo for NeXT

Our council of department heads meets in the dean's conference room, in the same building that houses the Departments of Theater and Art, among others. Before this morning's meeting, I noticed an Edward Tufte poster on the wall and went out to take a look. It turns out that the graphic design students were exhibiting posters they had made in one of their classes, while studying accomplished designers such as Tufte and Paul Rand, the creator of the NeXT logo for Steve Jobs.

As I browsed the gallery, I came across a couple of posters on the work of Charles and Ray Eames. One of them prominently featured this quote from Charles:

Design is a plan for arranging elements in such a way as best to accomplish a particular purpose.

This definition works just as well for software design as it does for graphic design. It is good to be reminded occasionally how universal the idea of design is to the human condition.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

November 18, 2011 2:10 PM

Teachers Working Themselves Out Of a Job

Dave Rooney wrote a recent entry on what he does when coaching in the realm of agile software development. He summarizes his five main tasks as:

  • Listen
  • Ask boatloads of questions
  • Challenge assumptions
  • Teach/coach Agile practices
  • Work myself out of a job

All but the fourth is a part of my job every day. Listening, asking questions, and challenging assumptions are essential parts of helping people to learn, whatever one's discipline or level of instruction. As a CS prof, I teach a lot of courses that instruct or require programming, and I look for opportunities to inject pragmatic programming skills and agile development practices.

What of working myself out of a job? For consultants like Rooney, this is indeed the goal: help an organization get on a track where they don't need his advice, where they can provide coaching from inside, and where they become sufficient in their own practices.

In a literal sense, this is not part of my job. If I do my job well, I will remain employed by the same organization, or at least have that option available to me.

But in another sense, my goals with respect to working myself out of a job are the same as as a consultant's, only at the level of individual students. I want to help students reach a point where they can learn effectively on their own. As much as possible, I hope for them to become more self-sufficient, able to learn as an equal member of the larger community of programmers and computer scientists.

A teacher's goal is, in part, to prepare students to move on to a new kind of learning, where they don't need us to structure the learning environment or organize the stream of ideas and information they learn from. Many students come to us pretty well able to do this already; they need only to realize that they don't me!

With most universities structured more around courses than one-on-one tutorials, I don't get to see the process through with every student I teach. One of the great joys is to have the chance to work with the same student many times over the years, through multiple courses and one-on-one through projects and research.

In any case, I think it's healthy for teachers to approach their jobs from the perspective of working themselves out of a job. Not to worry; there is always another class of students coming along.

Of course, universities as we know them may be disappearing. But the teachers among us will always find people who want to learn.


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

November 16, 2011 2:38 PM

Memories of a Programming Assignment

Last Friday afternoon, the CS faculty met with the department's advisory board. The most recent addition to the board is an alumnus who graduated a decade ago or so. At one point in the meeting, he said that a particular programming project from his undergraduate days stands out in his mind after all these years. It was a series of assignments from my Object-Oriented Programming course called Cat and Mouse.

I can't take credit for the basic assignment. I got the idea from Mike Clancy in the mid 1990s. (He later presented his version of the assignment on the original Nifty Assignments panel at SIGCSE 1999.) The problem includes so many cool features, from coordinate systems to stopping conditions. Whatever one's programming style or language, it is a fun challenge. When done OO in Java, with great support for graphics, it is even more fun.

But those properties aren't what he remembers best about the project. He recalls that the project took place over several weeks and that each week, I changed the requirements of assignment. Sometimes, I added a new feature. Other times, I generalized an existing feature.

What stands out in his mind after all these years is getting the new assignment each week, going home, reading it, and thinking,

@#$%#^. I have to rewrite my entire program.

You, see he had hard-coded assumptions throughout his code. Concerns were commingled, not separated. Objects were buried inside larger pieces of code. Model was tangled up with view.

So, he started from scratch. Over the course of several weeks, he built an object-oriented system. He came to understand dynamic polymorphism and patterns such as MVC and decorator, and found ways to use them effectively in his code.

He remembers the dread, but also that this experience helped him learn how to write software.

I never know exactly what part of what I'm doing in class will stick most with students. From semester to semester and student to student, it probably varies quite a bit. But the experience of growing a piece of software over time in the face of growing and changing requirements is almost always a powerful teacher.


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

November 14, 2011 3:43 PM

Using Null Object to Get Around Truthiness

Avdi Grimm recently posted a short but thorough introduction to a common problem encountered by Ruby programmers: nullifying an action when the required object is not present. In a mixed-paradigm language, this becomes an issue when we use if-statements to guard the action. Ruby, like many languages, treats a distinguished value as false and all other values as true. Thus, unless an object is "falsey", it will be seen as true by the if-statement. This requires us to do extra tests or wrap our objects to ensure that tests pass and fail at the appropriate times. Grimm explains the problem and walks us through several approaches to solving this problem in Ruby. I recommend you read it.

Some of my functional programming friends teased me about this article, along the lines of a pithy tweet:

Rubyists have discovered Maybe/Option.

Maybe is a wrapper type in Haskell that allows programmers to indicate that an expected value may not be available; Option is the Scala analog. Wrapper types are the natural way to handle the problem of falsey-ness in functional programming, especially in statically-typed languages. (Clojure, a popular dynamically-typed functional language in the Lisp tradition, doesn't make use of this idea.)

When I write Haskell code, as rare as that is, I use Maybe as a natural part of typing my programs. As a functional programmer more generally, I see its great value in writing compact code. The alternative in Scheme is to us if expressions to switch on value, separating null (usually) base cases from inductive cases.

However, when I work as an OO programmer, I don't miss Maybe or even falsey objects more generally. Indeed, I think the best advice in Grimm's article comes in his conclusion:

If we're trying to coerce a homemade object into acting falsey, we may be chasing a vain ideal. With a little thought, it is almost always possible to transform code from typecasing conditionals to duck-typed polymorphic method calls. All we have to do is remember to represent the special cases as objects in their own right, whether that be a Null Object or something else.

My pithy tweet-like conclusion is this: If you are checking for truthiness, you're doing OO wrong.

To do it right, use the Null Object pattern.

Ruby is an OO language, but it gives us great freedom to write code in other styles as well. Many programmers in the Ruby community, mostly those without prior OO experience, miss out on the beauty and compactness one can achieve using standard OO patterns.

I see a lot of articles on the web about the Null Object pattern, but most of them involve extending the class NilClass or its lone instance, nil. That is fine if you are trying to add generic null object behavior to a system, often in service of truthiness and falsey-ness. A better approach in most contexts is to implement an object that behaves like a "nothing" in your application. If you are writing a program that consist of users, create an unassigned user. If you are creating a logging facility and need the ability for a service not to use a log, create a null log. If you are creating an MVC application and need a read-only controller, create a null controller.

In some applications, the idea of the null object disappears into another primitive object. When we implement a binary tree, we create an object that has references to two other tree objects. If all tree nodes behave similarly except that some do not have children, then we can create a NullTree object to serve as the values of the instance variables in the actual leaves. If leaf nodes behave differently than interior nodes, then we can create a Leaf object to serve as the values of the interior nodes' instance variables. Leaf subsumes any need for a null object.

One of the consequences of using the Null Object pattern is the elimination of if statements that switch on the type of object present. Such if statements are a form of ad hoc polymorphism. Programmers using if statements while trying to write OO code should not be surprised that their lives are more difficult than they need be. The problem isn't with OOP; it's with not taking advantage of dynamic polymorphism, one of the essential benefits of OOP.

If you would like to learn more about the Null Object pattern, I suggest you read its two canonical write-ups:

If you are struggling with making the jump to OOP, away from typecasing switch statements and explicit loops over data structures, take up the programming challenge writing increasingly larger programs with no if statements and no for statements. Sometimes, you have to go to extremes before you feel comfortable in the middle.


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

November 12, 2011 10:40 AM

Tools, Software Development, and Teaching

Last week, Bret Victor published a provocative essay on the future of interaction design that reminds us we should be more ambitious in our vision of human-computer interaction. I think it also reminds us that we can and should be more ambitious in our vision of most of our pursuits.

I couldn't help but think of how Victor's particular argument applies to software development. First he defines "tool":

Before we think about how we should interact with our Tools Of The Future, let's consider what a tool is in the first place.

I like this definition: A tool addresses human needs by amplifying human capabilities.

a tool addresses human needs by amplifying human capabilities

That is, a tool converts what we can do into what we want to do. A great tool is designed to fit both sides.

The key point of the essay is that our hands have much more consequential capabilities than our current interfaces use. They feel. They participate with our brains in numerous tactile assessments of the objects we hold and manipulate: "texture, pliability, temperature; their distribution of weight; their edges, curves, and ridges; how they respond in your hand as you use them". Indeed, this tactile sense is more powerful than the touch-and-slide interfaces we have now and, in many ways, is more powerful than even sight. These tactile senses are real, not metaphorical.

As I read the essay, I thought of the software tools we use, from language to text editors to development processes. When I am working on a program, especially a big one, I feel much more than I see. At various times, I experience discomfort, dread, relief, and joy.

Some of my colleagues tell me that these "feelings" are metaphorical, but I don't think so. A big part of my affinity for so-called agile approaches is how these sensations come into play. When I am afraid to change the code, it often means that I need to write more or better unit tests. When I am reluctant to add a new feature, it often means that I need to refactor the code to be more hospitable. When I come across a "code smell", I need to clean up, even if I only have time for a small fix. YAGNI and doing the simplest thing that can possibly work are ways that I feel my way along the path to a more complete program, staying in tune with the code as I go. Pair programming is a social practice that engages more of my mind than programming alone.

Victor closes with some inspiration for inspiration:

In 1968 -- three years before the invention of the microprocessor -- Alan Kay stumbled across Don Bitzer's early flat-panel display. Its resolution was 16 pixels by 16 pixels -- an impressive improvement over their earlier 4 pixel by 4 pixel display.

Alan saw those 256 glowing orange squares, and he went home, and he picked up a pen, and he drew a picture of a goddamn iPad.

We can think bigger about so much of what we do. The challenge I take from Victor's essay is to think about the tools I to teach: what needs do they fulfill, and how well do they amplify my own capabilities? Just as important are the tools we give our students as they learn: what needs do they fulfill, and how well do they amplify our students' capabilities?


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

October 27, 2011 6:44 PM

A Perfect Place to Cultivate an Obsession

And I urge you to please notice when you are happy,
and exclaim or murmur or think at some point,
"If this isn't nice, I don't know what is."
-- Kurt Vonnegut, Jr.

I spent the entire day teaching and preparing to teach, including writing some very satisfying code. It was a way to spend a birthday.

With so much attention devoted to watching my students learn, I found myself thinking consciously about my teaching and also about some learning I have been doing lately, including remembering how to write idiomatic Ruby. Many of my students really want to be able to write solid, idiomatic Scheme programs to process little languages. I see them struggle with the gap between their desire and their ability. It brought to mind something poet Mary Jo Bang said in recent interview about her long effort to become a good writer:

For a long time the desire to write and knowing how to write well remained two separate things. I recognized good writing when I saw it but I didn't know how to create it.

I do all I can to give students examples of good programs from which they can learn, and also to help them with the process of good programming. In the end, the only way to close the gap is to write a lot of code. Writing deliberately and reflectively can shorten the path.

Bang sees the same in her students:

Industriousness can compensate for a lot. And industry plus imagination is a very promising combination.

Hard work is the one variable we all control while learning something new. Some of us are blessed with more natural capacity to imagine, but I think we can stretch our imaginations with practice. Some CS students think that they are learning to "engineer" software, a cold, calculating process. But imagination plays a huge role in understanding difficult problems, abstract problems.

Together, industry and time eventually close the gap between desire and ability:

And I saw how, if you steadily worked at something, what you don't know gradually erodes and what you do know slowly grows and at some point you've gained a degree of mastery. What you know becomes what you are. You know photography and you are a photographer. You know writing and you are a writer.

... You know programming, and you are a programmer.

Erosion and growth can be slow processes. As time passes, we sometimes find our learning accelerates, a sort of negative splits for mental exercise.

We work hardest when we are passionate about what we do. It's hard for homework assigned in school to arouse passion, but many of us professors do what we can. The best way to have passion is to pick the thing you want to do. Many of my best students have had a passion for something and then found ways to focus their energies on assigned work in the interest of learning the skills and gaining the experience they need to fulfill their passion.

One last passage from Bang captures perfectly for me what educators should strive to make "school":

It was the perfect place to cultivate an obsession that has lasted until the present.

As a teacher, I see a large gap between my desire to create the perfect place to cultivate an obsession and my ability to deliver. For, now the desire and the ability remain two separate things. I recognize good learning experiences when I see them, and occasionally I stumble into creating one, but I don't yet know how to create them reliably.

Hard work and imagination... I'll keep at it.

If this isn't nice, I don't know what is.


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

October 24, 2011 7:38 PM

Simple/Complex Versus Easy/Hard

A few years ago, I heard a deacon give a rather compelling talk to a group of college students on campus. When confronted with a recommended way to live or act, students will often say that living or acting that way is hard. These same students are frustrated with the people who recommend that way of living or acting, because the recommenders -- often their parents or teachers -- act as if it is easy to live or act that way. The deacon told the students that their parents and teachers don't think it is easy, but they might well think it is simple.

How can this be? The students were confounding "simple" and "easy". A lot of times, life is simple, because we know what we should do. But that does not make life easy, because doing a simple thing may be quite difficult.

This made an impression on me, because I recognized that conflict in my own life. Often, I know just what to do. That part is simple. Yet I don't really want to do it. To do it requires sacrifice or pain, at least in the short term. To do it means not doing something else, and I am not ready or willing to forego that something. That part is difficult.

Switch the verb from "do" to "be", and the conflict becomes even harder to reconcile. I may know what I want to be. However, the gap between who I am and who I want to be may be quite large. Do I really want to do what it takes to get there? There may be a lot of steps to take which individually are difficult. The knowing is simple, but the doing is hard.

This gap surely faces college students, too, whether it means wanting to get better grades, wanting to live a healthier life, or wanting to reach a specific ambitious goal.

When I heard the deacon's story, I immediately thought of some of my friends, who like very much the idea of being a "writer" or a "programmer", but they don't really want to do the hard work that is writing or programming. Too much work, too much disappointment. I thought of myself, too. We all face this conflict in all aspects of life, not just as it relates to personal choices and values. I see it in my teaching and learning. I see it in building software.

I thought of this old story today when I watched Rich Hickey's talk from StrangeLoop 2011, Simple Made Easy. I had put off watching this for a few days, after tiring of a big fuss that blew up a few weeks ago over Hickey's purported views about agile software development techniques. I knew, though, that the dust-up was about more than just Hickey's talk, and several of my friends recommended it strongly. So today I watched. I'm glad I did; it is a good talk. I recommend it to you!

Based only on what I heard in this talk, I would guess that Hickey misunderstands the key ideas behind XP's practices of test-driven development and refactoring. But this could well be a product of how some agilistas talk about them. Proponents of agile and XP need to be careful not to imply that tests and refactoring make change or any other part of software development easy. They don't. The programmer still has to understand the domain and be able to think deeply about the code.

Fortunately, I don't base what I think about XP practices on what other people think, even if they are people I admire for other reasons. And if you can skip or ignore any references Hickey makes to "tests as guard rails" or to statements that imply refactoring is debugging, I think you will find this really is a very good talk.

Hickey's important point is that simple/complex and easy/hard are different dimensions. Simplicity should be our goal when writing code, not complexity. Doing something that is hard should be our goal when it makes us better, especially when it makes us better able to create simplicity.

Simplicity and complexity are about the interconnectedness of a system. In this dimension, we can imagine objective measures. Ease and difficulty are about what is most readily at hand, what is most familiar. Defined as they are in terms of a person's experience or environment, this dimension is almost entirely subjective.

And that is good because, as Hickey says a couple of times in the talk, "You can solve the familiarity problem for yourself." We are not limited to our previous experience or our current environment; we can take on a difficult challenge and grow.

a Marin mountain bike

Alan Kay often talks about how it is worth learning to play a musical instrument, even though playing is difficult, at least at the start. Without that skill, we are limited in our ability to "make music" to turning on the radio or firing up YouTube. With it, you are able make music. Likewise riding a bicycle versus walking, or learning to fly an airplane versus learning to drive a car. None of these skills is necessarily difficult once we learn them, and they enable new kinds of behaviors that can be simple or complex in their own right.

One of the things I try to help my students see is the value in learning a new, seemingly more difficult language: it empowers us to think new and different thoughts. Likewise making the move from imperative procedural style to OOP or to functional programming. Doing so stretches us. We think and program differently afterward. A bonus is that something that seemed difficult before is now less daunting. We are able to work more effectively in a bigger world.

In retrospect, what Hickey says about simplicity and complexity is actually quite compatible with the key principles of XP and other agile methods. Writing tests is a part of how we create systems that are as simple as we can in the local neighborhood of a new feature. Tests can also help us to recognize complexity as it seeps into our program, though they are not enough by themselves to help us see complexity. Refactoring is an essential part of how we eliminate complexity by improving design globally. Refactoring in the presence of unit tests does not make programming easy. It doesn't replace thinking about design; indeed, it is thinking about design. Unit tests and refactoring do help us to grapple with complexity in our code.

Also in retrospect, I gotta make sure I get down to St. Louis for StrangeLoop 2012. I missed the energy this year.


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

October 06, 2011 3:21 PM

Programming != Teaching

A few weeks ago I wrote a few entries that made connections to Roger Rosenblatt's Unless It Moves the Human Heart: The Craft and Art of Writing. As I am prone to doing, I found a lot of connections between writing, as described by Rosenblatt, and programming. I also saw connections between teaching of writers and teaching of programmers. The most recent entry in that series highlighted how teachers want their students to learn how to think the same way, not how to write the same way.

Rosenblatt also occasionally explores similarities between writing and teaching. Toward the end of the book, he points out a very important difference between the two:

Wouldn't it be nice if you knew that your teaching had shape and unity, and that when a semester came to an end, you could see that every individual thing you said had coalesced into one overarching statement? But who knows? I liken teaching to writing, but the two enterprises diverge here, because any perception of a grand scheme depends on what the students pick up. You may intend a lovely consistency in what you're tossing them, but they still have to catch it. In fact, I do see unity to my teaching. What they see, I have no clue. It probably doesn't matter if they accept the parts without the whole. A few things are learned, and my wish for more may be plain vanity.

Novelists, poets, and essayists can achieve closure and create a particular whole. Their raw material are words and ideas, which the writer can make to dance. The writer can have an overarching statement in mind, and making it real is just a matter of hard work and time.

Programmers have that sort of control over their raw material, too. As a programmer, I relish taken on the challenge of a hard problem and creating a solution that meets the needs of a person. If I have a goal for a program, I can almost always make it happen. I like that.

Teachers may have a grand scheme in mind, too, but they have no reliable way of making sure that their scheme comes true. Their raw material consists not only of words and ideas. Indeed, their most important raw material, their most unpredictable raw material, are students. Try as they might, teachers don't control what students do, learn, or think.

I am acutely aware of this thought as we wrap up the first half of our programming languages course. I have introduced students to functional programming and recursive programming techniques. I have a pretty good idea what I hope they know and can do now, but that scheme remains in my head.

Rosenblatt is right. It is vanity for us teachers to expect students to learn exactly what we want for them. It's okay if they don't. Our job is to do what we can to help them grow. After that, we have to step aside and let them run.

Students will create their own wholes. They will assemble their wholes from the parts they catch from us, but also from parts they catch everywhere else. This is a good thing, because the world has a lot more to teach than I can teach them on my own. Recognizing this makes it a lot easier for me as a teacher to do the best I can to help them grow and then get out of their way.


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

October 03, 2011 8:11 AM

What to Build and How to Build

Update: This entry originally appeared on September 29. I bungled my blog directory and lost two posts, and the simplest way to get the content back on-line is to repost.

I remember back in the late 1990s and early 2000s when patterns were still a hot topic in the software world, and many pattern writers trying to make the conceptual move to pattern languages. It was a fun time to talk about software design. At some point, there was a long and illuminating discussion on the patterns mailing list about whether patterns should describe what to build or how to build. Richard Gabriel and Ron Goldman -- creators of the marvelous essay-as-performance-art Mob Software -- patiently taught the community that the ultimate goal is what. Of course, if we move to a higher level of abstraction, a what-pattern becomes a how-pattern. But the most valuable pattern languages teach us what to build and when, with some freedom in the how.

This is the real challenge that novice programmers face, in courses like CS1 or in self-education: figuring out what to build. It is easy enough for many students to "get" the syntax of the programming language they are learning. Knowing when to use a loop, or a procedure, or a class -- that's the bigger challenge.

Our CS students are usually in the same situation even later in their studies. They are still learning what to build, even as we teach them new libraries, new languages, and new styles.

I see this a lot when students who are learning to program in a functional style. Mentally, many think they are focused on the how (e.g., How do I write this in Scheme?). But when we probe deeper, we usually find that they are really struggling with what to say. We spend some time talking about the problem, and they begin to see more clearly what they are trying to accomplish. Suddenly, writing the code becomes a lot easier, if not downright easy.

This is one of the things I really respect in the How to Design Programs curriculum. Its design recipes give beginning students a detailed, complete, repeatable process for thinking about problems and what they need to solve a new problem. Data, contracts, and examples are essential elements in understanding what to build. Template solutions help bridge the what and the how, but even they are, at the student's current level of abstraction, more about what than how.

The structural recursion patterns I use in my course are an attempt to help students think about what to build. The how usually follows directly from that. As students become fluent in their functional programming language, the how is almost incidental.


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

October 03, 2011 7:20 AM

Softmax, Recursion, and Higher-Order Procedures

Update: This entry originally appeared on September 28. I bungled my blog directory and lost two posts, and the simplest way to get the content back on-line is to repost.

John Cook recently reported that he has bundled up some of his earlier writings about the soft maximum as a tech report. The soft maximum is "a smooth approximation to the maximum of two real variables":

    softmax(x, y) = log(exp(x) + exp(y))

When John posted his first blog entry about the softmax, I grabbed the idea and made it a homework problem for my students, who were writing their first Scheme procedures. I gave them a link to John's page, so they had access to this basic formula as well as a Python implementation of it. That was fine with me, because I was simply trying to help students become more comfortable using Scheme's unusual syntax:

    (define softmax
      (lambda (x y)
        (log (+ (exp x)
                (exp y)))))

On the next assignment, I asked students to generalize the definition of softmax to more than two variables. This gave them an opportunity to write a variable arity procedure in Scheme. At that point, they had seen only a couple simple examples of variable arity, such as this implementation of addition using a binary + operator:

    (define plus              ;; notice: no parentheses around
      (lambda args            ;; the args parameter in lambda
        (if (null? args)
            0
            (+ (car args) (apply plus (cdr args))) )))

Many students followed this pattern directly for softmax:

    (define softmax-var
      (lambda args
        (if (null? (cdr args))
            (car args)
            (softmax (car args)
                     (apply softmax-var (cdr args))))))

Some of their friends tried a different approach. They saw that they could use higher-order procedures to solve the problem -- without explicitly using recursion:

    (define softmax-var
      (lambda args
        (log (apply + (map exp args)))))

When students saw each other's solutions, they wondered -- as students often do -- which one is correct?

John's original blog post on the softmax tells us that the function generalizes as we might expect:

    softmax(x1, x2, ..., xn) = log(exp(x1) + exp(x2) + ... + exp(xn))

Not many students had looked back for that formula, I think, but we can see that it matches the higher-order softmax almost perfectly. (map exp args) constructs a list of the exp(xi) values. (apply + ...) adds them up. (log ...) produces the final answer.

What about the recursive solution? If we look at how its recursive calls unfold, we see that this procedure computes:

    softmax(x1, softmax(x2, ..., softmax(xn-1, xn)...))

This is an interesting take on the idea of a soft maximum, but it is not what John's generalized definition says, nor is it particularly faithful to the original 2-argument function.

How might we roll our own recursive solution that computes the generalized function faithfully? The key is to realize that the function needs to iterate not over the maximizing behavior but the summing behavior. So we might write:

    (define softmax-var
      (lambda args
        (log (accumulate-exps args))))

(define accumulate-exps (lambda (args) (if (null? args) 0 (+ (exp (car args)) (accumulate-exps (cdr args))))))

This solution turns softmax-var into interface procedure and then uses structural recursion over a flat list of arguments. One advantage of using an interface procedure is that the recursive procedure accumulate-exps no longer has to deal with variable arity, as it receives a list of arguments.

It was remarkable to me and some of my students just how close the answers produced by the two student implementations of softmax were, given how different the underlying behaviors are. Often, the answers were identical. When different, they differed only in the 12th or 15th decimal digit. As several blog readers pointed out, softmax is associative, so the two solutions are identical mathematically. The differences in the values of the functions result from the vagaries of floating-point precision.

The programmer in me left the exercise impressed by the smoothness of the soft maximum. The idea is resilient across multiple implementations, which makes it seem all the more useful to me.

More important, though, this programming exercise led to several interesting discussions with students about programming techniques, higher-order procedures, and the importance of implementing solutions that are faithful to the problem domain. The teacher in me left the exercise pleased.


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

September 24, 2011 8:04 PM

Much Code To Study, Learning with Students

I mentioned last time that I've been spending some time with Norvig's work on Strachey's checkers program in CPL. This is fun stuff that can be used in my programming languages course. But it isn't the only new stuff I've been learning. When you work with students on research projects and independent studies, opportunities to learn await at every turn.

A grad student is taking the undergrad programming languages course and so has to do some extra projects to earn his grad credit. He is a lover of Ruby and has been looking at a couple of Scheme interpreters implemented in Ruby, Heist and Bus-Scheme. I'm not sure where this will lead yet, but that is part of the exercise. The undergrad who faced the "refactor or rewrite?" decision a few weeks ago teaches me something new every week, not only through his experiences writing a language processor but also about his program's source and target languages, Photoshop and HTML/CSS.

Another grad student is working on a web application and teaching me other things about Javascript. Now we are expanding into one tool I've long wanted to study in greater detail, Processing.js and perhaps into another I only just learned of from Dave Humphrey, a beautiful little data presentation library called D3.

And as if that weren't enough, someone tweets that Avdi Grimm is sharing is code and notes as he implements Smalltalk Best Practice Patterns in Ruby. Awesome. This Avdi guy is rapidly becoming one of my heroes.

All of these projects are good news. One of the great advantages of working at a university is working with students and learning along with him. Right now, I have a lot on my plate. It's daunting but fun.


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

September 13, 2011 7:17 PM

Learning to Think the Same, Not Write the Same

We have begun to write code in my programming languages course. The last couple of sessions we have been writing higher-order procedures, and next time we begin a three-week unit learning to write recursive programs following the structural recursion patterns in my small pattern language Roundabout.

One of the challenges for students is to learn how to use the patterns without feeling a need to mimic my style perfectly. Some students, especially the better ones, will chafe if I try to make them write code exactly as I do. They are already good programmers in other styles, and they can become good functional programmers without aping me. Many will see the patterns as a restriction on how they think, though in fact the patterns are source of great freedom. They force you to write code in a particular way; they give you tools for thinking about problems as you program.

Again, there is something for us to learn from our writing brethren. Consider a writing course like the one Roger Rosenblatt describes in his book, Unless It Moves the Human Heart: The Craft and Art of Writing, which I have referred to several times, most recently in The Summer Smalltalk Taught Me OOP. No student in Rosenblatt's course wants him to expect them to leave the course writing just like he does. They are in the course to learn elements of craft, to share and critique work, and to get advice from someone with extensive experience as a writer. Rosenblatt is aware of this, too:

Wordsworth quoted Coleridge as saying that every poet must create the taste by which he is relished. The same is true of teachers. I really don't want my students to write as I do, but I want them to think about writing as I do. In them I am consciously creating a certain taste for what I believe constitutes skillful and effective writing.

The course is more about learning how to think about writing as much as it is about learning how to write itself. That's what a good pattern language can do for us: help us learn to think about a class of problems or a class of solutions.

I think this happens whether a teacher intends it consciously or not. Students learn how to think and do by observing their teachers thinking and doing. A programming course is usually better if the teacher designs the course deliberately, with careful consideration of the patterns to demonstrate and the order in which students experience them in problems and solutions.

In the end, I want my students to think about writing recursive programs as I do, because experience as both a programmer and as a teacher tells me that this way of thinking will help them become good functional programmers as soon as possible. But I do not want them to write exactly as I so; they need to find their own style, their own taste.

This is yet another example of the tremendous power teachers wield every time they step foot in a classroom. As a student, I was always most fond of the teachers wielded it carefully and deliberately. So many of them live on in me in how I think. As a teacher, I have come to respect this power in my own hands and try to wield it respectfully with my students.

P.S. For what it's worth, Coleridge is one of my favorite poets!


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

September 12, 2011 12:14 PM

You Keep Using That Word....

Inigo Montoya, from The Princess Bride

Elisabeth Hendrickson recently posted a good short piece about Testing is a Whole Team Activity. She gives examples of some of the comments she hears frequently which indicate a misunderstanding about the relationship between coding and testing. My favorite example was the first:

"We're implementing stories up to the last minute, so we can never finish testing within the sprint."

Maybe I like this one so much because I hear it from students so often, especially on code that they find challenging and are having a hard time finishing.

"If we took the time to test our code, we would not get done on time."

"What evidence do you have that your code works for the example cases?"

"Well, none, really, but..."

"Then how do you know you are done?"

"'done'?" You keep using that word. I do not think it means what you think it means.


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

September 08, 2011 8:19 PM

The Summer Smalltalk Taught Me OOP

Or, Throw 'em Away Until You Get It Right

Just before classes started, one of my undergrad research students stopped by to talk about a choice he was weighing. He is writing a tool that takes as input a Photoshop document and produces as output a faithful, understandable HTML rendition of the design and content. He has written a lot of code in Python over the last few months, using an existing library of tools for working with Photoshop docs. Now that he understands the problem well and has figured out what a good solution looks like, he is dissatisfied with his existing code. He thinks he can create a better, simpler solution by writing his own Photoshop-processing tools.

The choice is: refactor the code incrementally until he has replaced all the library code, or start from scratch?

My student's dilemma took me back over twenty years, to a time when I faced the same choice, when I too was first learning my craft.

I was one of my doctoral advisor's first graduate students. In AI, this means that we had a lot of infrastructure to build in support of the research we all wanted to do. We worked in knowledge-based systems, and in addition to doing research in the lab we also wanted to deliver working systems to our collaborators on and off campus. Building tools for regular people meant having reasonable interfaces, preferably with GUI capabilities. This created an extra problem, because our collaborators used PCs, Macs, and Unix workstations. My advisor was a Mac guy. At the time, I was a Unix man in the process of coming to love Macs. In that era, there was no Java and precious few tools for writing cross-platform GUIs.

Our lab spent a couple of years chasing the ideal solution: a way to write a program and run it on any platform, giving users the same experience on all three. The lab had settled more or less on PCL, a portable Common Lisp. It wasn't ideal, but we grad students -- who were spending a lot of time implementing libraries and frameworks -- were ready to stop building infrastructure and start working full-time on our own code.

the Smalltalk balloon from Byte magazine

Then my advisor discovered Smalltalk.

The language included graphics classes in its base image, which offered the promise of write-once-run-anywhere apps for clients. And it was object-oriented, which matched the conceptual model of the software we wanted to build to a T. I had just spent several months trying to master CLOS, Common Lisp's powerful object system, but Smalltalk looked like just what we wanted. So we made the move -- and told advisor that this would be the last move. Smalltalk would be our home.

I learned the basics of the language by working through every tutorial I could my hands on, first Digitalk Smalltalk then ObjectWorks. They were pretty good. Then I wrote some toy programs of my own, to show I was ready to create on my own.

So I started writing my first Smalltalk system: a parser and interpreter for a domain-specific AI language with a built-in inference engine, a simple graphical and table-driven tool for writing programs in these languages, and graphical front end for running systems.

There was a lot going on there, at least for a green graduate student only recently called up to the big leagues. But I had done my homework. I was ready. I was sure of it. I was cocky.

I crashed.

It turn out that I didn't really understand the role that data should play in an OO program. My program soon became a tangle of data dependencies design before I understood my solution all that well, and the tangle made the code increasing turgid.

So I threw it away, rm -r'ed it into nothingness. I started from scratch, sure that Version 2 would be perfect.

I crashed again.

The program was better this time around, but it turns out that I didn't really understand how objects should interact in a large OO program. My program soon became a tangle of objects and wrappers and adapters, whose behavior I could not follow in even the simplest scenarios. The tangle made the code increasing murky.

So I threw it away -- rm -r again -- and started from scratch. Surely Version 3, based on several weeks of coding and learning, would be just what we wanted.

I crashed yet again. This time, the landing was more gentle, because I really was making progress. But as I coded my third system, I began to see ways to structure the program that would make the code easier to grow as I added features, and easier to change as I got better at design. I was just beginning to glimpse the Land of Design Patterns. But I always seemed to learn each lesson one day too late to use it.

My program was moving forward, creakily, but I just knew it could be better. I did not like the idea of maintaining this code for several years, as we modified apps fielded with our collaborators and as we used it as part of the foundation for the lab's vision.

So I threw it away and wrote my system from scratch one last time. The result was not a perfect program, but one that I could live with and be proud of. It only took me four major iterations and several months of programming.

Looking back, I faced the same decision my student faced recently with his system. Refactor or start over? He has the advantage of having written a better first program than I had, yet he made the sound decision to rewrite.

Sometimes, refactoring really is the better approach. You can keep system running while slowly corralling data dependencies, spurious object interactions, and suboptimal design. Had I been a more experienced programmer, I may well have chosen to refactor from Version 3 to Version 4 of my program. But I wasn't. Besides, I had neither a suite of unit tests nor access to automated refactoring tools. Refactoring without either of these makes the process scarier and more dangerous than it needs to be.

Maybe refactoring is the better approach most or all of the time. I've read all about how the Great Rewrite is one of those Things You Should Never Do.

Fred Brooks

But then, there is an axiom from Turing Award winner Fred Brooks that applies better to my circumstance of writing the initial implementation of a program: "... plan to throw one away; you will, anyhow". I find Brooks's advice most useful when I am learning a lot while I am programmer. For me, that is one context, at least, in which starting from scratch is a big win: when my understanding is changing rapidly, whether of domain, problem, or tools. In those cases, I am usually incapable of refactoring fast enough to keep up with my learning. Starting over offers a faster path to a better program than refactoring.

On that first big Smalltalk project of mine, I was learning so much, so fast. Smalltalk was teaching me object-oriented programming, through my trial and error and through my experience with the rest of the Smalltalk class hierarchy. I had never written a language interpreter or other system of such scale before, and I was learning lessons about modularity and language processing. I was eager to build a new and improved system as quickly as I could.

In such cases, there is nothing like the sound of OS X's shredder. Freedom. No artificial constraints from what has suddenly become legacy code. No limits from my past ignorance. A fresh start. New energy!

This is something we programmers can learn from the experience of other writers, if we are willing. In Unless It Moves the Human Heart: The Craft and Art of Writing, Roger Rosenblatt tells us that Edgar Doctorow ...

... had written 150 pages of The Book of Daniel before he'd realized he had chosen the wrong way to tell the story. ... So one morning Edgar tossed out the 150 pages and started all over.... I wanted the class to understand that Edgar was happy to start from scratch, because he had picked the wrong door the first time.

Sometimes, the best thing a programmer can admit is that he or she has picked the wrong door and walked down the wrong path.

But Brooks warns of a danger programmer's face on second efforts: the Second System Effect. As Scott Rosenberg writes in Code Reads #1: The Mythical Man-Month:

Brooks noted that an engineer or team will often make all the compromises necessary to ship their first product, then founder on the second. Throughout project number one, they stored up pet features and extras that they couldn't squeeze into the original product, and told themselves, "We'll do it right next time." This "second system" is "the most dangerous a man ever designs."

I never shipped the first version of my program, so perhaps I eluded this pitfall out of luck. Still, I was cocky when I wrote Version 1, and then I was cocky when I wrote Version 2. But both versions humbled me, humbled me hard. I was a good programmer, maybe, but I wasn't good enough. I had a lot to learn, and I wanted to learn it all.

So it was relatively easy to start over on #3 and #4. I was learning, and I had the luxury of time. Ah, to be a grad student again!

In the end, I wrote a program that I could release to users and colleagues with pride. Along the way, Smalltalk taught me a lot about OOP, and writing the program taught me a lot about expert system shells. It was time well spent.


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

September 04, 2011 7:28 PM

In Praise of Usefulness

In two recent entries [ 1 | 2 ], I mentioned that I had been recently reading Roger Rosenblatt's Unless It Moves the Human Heart: The Craft and Art of Writing. Many of you indulge me my fascination with writers talking about writing, and I often see parallels between what writers of code and writers of prose and poetry do. That Rosenblatt also connects writing to teaching, another significant theme of my blog, only makes this book more stimulating to me.

"Unless it moves the human heart" is the sort of thing writers say about their calling, but not something many programmers say. (The book title quotes Aussie poet A. D. Hope.) It is clearly at the heart of Rosenblatt's views of writing and teaching. But in his closing chapter, Rosenblatt includes a letter written to his students as a postscript on his course that speaks to a desire most programmers have for the lives' work: usefulness. To be great, he says, your writing must be useful to the world. The fiction writer's sense of utility may differ from the programmer's, but at one level the two share an honorable motive.

This paragraph grabbed me as advice as important for us programmers as it is for creative programmers. (Which software people do you think of as you read it?)

How can you know what is useful to the world? The world will not tell you. The world will merely let you know what it wants, which changes from moment to moment, and is nearly always cockeyed. You cannot allow yourself to be directed by its tastes. When a writer wonders, "Will it sell?" he is lost, not because he is looking to make an extra buck or two, but rather because, by dint of asking the question in the first place, he has oriented himself to the expectations of others. The world is not a focus group. The world is an appetite waiting to be defined. The greatest love you can show it is to create what it needs, which means you must know that yourself.

What a brilliant sentence: The world is an appetite waiting to be defined. I don't think Ward Cunningham went around asking people if they needed wiki. He built it and gave it to them, and when they saw it, their appetite took form. It is indeed a great form of love to create what the world needs, whether the people know it yet or not.

(I imagine that at least a few of you were thinking of Steve Jobs and the vision that gave us the Mac, iTunes, and the iPad. I was too, though Ward has always been my hero when it comes to making useful things I had not anticipated.)

Rosenblatt tells his students that, to write great stories and poems and essays, they need to know the world well and deeply. This is also sound advice to programmers, especially those who want to start the next great company or revolutionize their current employers from the inside out. This is another good reason to read, study, and think broadly. To know the world outside of one's Ruby interpreter, outside the Javascript spec and the HTML 5.0, one must live in it and think about it.

It seems fitting on this Labor Day weekend for us to think about all the people who make the world we live in and keep it running. Increasingly, those people are using -- and writing -- software to give us useful things.


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

August 27, 2011 9:36 AM

Extravagant Ideas

One of the students in my just-started Programming Languages course recently mentioned that he has started a company, Glass Cannon Games, to write games for the Box and Android platforms. He is working out of my university's student incubator.

Last summer, I wrote a bit about entrepreneurship and a recent student of mine, Nick Cash, who has started Book Hatchery to "help authors publish their works digitally".

Going a bit further back, I mentioned an alumnus, Wade Arnold, winning a statewide award for his company, T8 Webware. Readers of this blog most recently encountered Wade in my entry on the power of intersections.

Over the last decade, Wade has taken a few big ideas and worked hard to make them real. That's what Nick and, presumably, Ian are doing, too.

Most entrepreneurs start with big thoughts. I try to encourage students to think big thoughts, to consider an entrepreneurial career. The more ideas they have, the more options they have in careers and in life. Going to work for a big company is the right path for some, but some want more and can do their own thing -- if only they have the courage to start.

This is a more important idea than just for starting start-ups. We can "think big and write small" even for the more ordinary programs we write. Sometimes we need a big idea to get us started writing code. Sometimes, we even need hubris. Every problem a novice faces can appear bigger than it is. Students who are able to think big often have more confidence. That is the confidence they need to start, and to persevere.

It is fun as a teacher to be able to encourage students to think big. As writer Roger Rosenblatt says,

One of the pleasures of teaching writing courses is that you can encourage extravagant thoughts like this in your students. These are the thoughts that will be concealed in plain and modest sentences when they write. But before that artistic reduction occurs, you want your students to think big and write small.

Many students come into our programming courses unsure, even a little afraid. Helping them free themselves to have extravagant ideas is one of the best things a teacher can do for them. Then they will be motivated to do the work they need to master syntax and idioms, patterns and styles.

A select few of them will go a step further and believe something even more audacious, that

... there's no purpose to writing programs unless you believe in significant ideas.

Those will be the students who start the Glass Cannons, the Book Hatcheries, and the T8s. We are all better off when they do.


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

August 26, 2011 2:29 PM

Thoughts at the Start of the Semester

We have survived Week 1. This semester, I again get to teach Programming Languages, a course I love and about which I blog for a while every eighteen months of so.

I had thought I might blog as I prepped for the course, but between my knee and department duties, time was tight. I've also been slow to settle on new ideas for the course. In my blog ideas folder, I found notes for an entry debriefing the last offering of the course, from Spring 2010, and thought that might crystallize some ideas for me. Alas, the notes held nothing useful. They were just a reminder to write, which went unheeded during a May term teaching agile software development.

Yesterday I started reading a new book -- not a book related to my course, but Roger Rosenblatt's Unless It Moves the Human Heart: The Craft and Art of Writing. I love to read writers talking about writing, and this book has an even better premise: it is a writer talking about writing as he teaches writing to novices! So there is plenty of inspiration in it for me, even though it contains not a single line of Scheme or Ruby.

Rosenblatt recounts teaching a course a course called "Writing Everything". Most the students in the course want to learn how to write fiction, especially short stories. Rosenblatt has them also read write poems, in which they can concentrate on language and sounds, and essays, in which they can learn to develop ideas.

This is not the sort of course you find in CS departments. The first analogy that came to mind was a course in which students wrote, say, a process scheduler for an OS, a CRUD database app for a business, and an AI program. The breadth and diversity of apps might get the students to think about commonalities and differences in their programming practice. But a more parallel course would ask students to write a few procedural programs, object-oriented programs, and functional programs. Each programming style would let the student focus on different programming concepts and distinct elements of their craft.

I'd have a great time teaching such a "writing" course. Writing programs is fun and hard to learn, and we don't have many opportunities in a CS program to talk about the process of writing and revising code. Software engineering courses have a lot of their own content, and even courses on software design and development often deal more with new content than with programming practice. In most people's minds, there is not room for a new course like this one in the curriculum. In CS programs, we have theory and applications courses to teach. In Software Engineering programs, they seem far too serious about imitating other engineering disciplines to have room for something this soft. If only more schools would implement Richard Gabriel's idea of an MFA in software...

Despite all these impediments, I think a course in which students simply practiced programming in the large(r) and focused on their craft could be of great value to most CS grads.

I will let Rosenblatt's book inspire me and leak into my Programming Languages course where helpful. But I will keep our focus on the content and skills that our curriculum specifies for the course. By learning the functional style of programming and a lot about how programming languages work, students will get a chance to develop a few practical skills, which we hope will pay off in helping them to be better programmers all around, whether in Java, Python, Ruby, Scala, Clojure, or Ada.

One meta-message I hope to communicate both explicitly and implicitly is that programmers never stop learning, including their professor. Rosenblatt has the same goal in his writing course:

I never fail to say "we" to my students, because I do not want them to get the idea that you ever learn how to write, no matter how long you've done it.

Beyond that, perhaps the best I can do is let my students that I am still mesmerized by the cool things we are learning. As Rosenblatt says,

Observing a teacher who is lost in the mystery of the material can be oddly seductive.

Once students are seduced, they will take care of their own motivation and their own learning. They won't be able to help themselves.


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

August 21, 2011 9:32 AM

Overcoming a Disconnect Between Knowing and Doing

Before reading interviews with Hemingway and Jobs, I read a report of Ansel Adams's last interview. Adams was one of America's greatest photographers of the 20th century, of course, and several of his experiences seem to me to apply to important issues in software development.

It turns out that both photography and software development share a disconnect between teaching and doing:

One of the problems is the teaching of photography. In England, I was told, there's an institute in which nobody can teach photography until they've had five years' experience in the field, until they've had to make a go of it professionally.

Would you recommend that?

I think that teachers should certainly have far more experience than most of the ones I know of have had. I think very few of them have had practical experience in the world. Maybe it's an impossibility. But most of the teachers work pretty much the same way. The students differ more from each other than the teachers do.

Academics often teach without having experience making a living from the material they teach. In computer science, that may make sense for topics like discrete structures. There is a bigger burden in most of the topics we teach, which are done in industry and which evolve at a more rapid rate. New CS profs usually come out of grad school on the cutting edge of their specialties, though not necessarily on top of all the trends in industry. Those who take research-oriented positions stay on the cutting edge of their areas, but the academic pressure is often to become narrower in focus and thus farther from contemporary practice. Those who take positions at teaching schools have to work really hard to stay on top of changes out in the world. Teaching a broad variety of courses makes it difficult to stay on top of everything.

Adams's comment does not address the long-term issue, but it takes a position on the beginning of careers. If every new faculty member had five years or professional programming experience, I dare say most undergrad CS courses would be different. Some of the changes might be tied too closely to those experiences (someone who spent five years at Rockwell Collins writing SRSs and coding in Ada would learn different things from someone who spent five years writing e-commerce sites in Rails), but I think would usually be some common experiences that would improve their courses.

When I first read Adams's comment, I was thinking about how the practitioner would learn and hone elements of craft that the inexperienced teacher didn't know. But the most important thing that most practitioners would learn is humility. It's easy to lecture rhapsodically about some abstract approach to software development when you haven't felt the pain it causes, or faced the challenges left even when it succeeds. Humility can be a useful personal characteristic in a teacher. It helps us see the student's experience more accurately and to respond by changing how and what we teach.

Short of having five years of professional experience, teachers of programming and software development need to read and study all the time -- and not just theoretical tomes, but also the work of professional developers. Our industry is blessed with great books by accomplished developers and writes, such as Design Patterns and Refactoring. The web and practitioners' conferences such as StrangeLoop are an incredible resource, too. As Fogus tweeted recently, "We've reached an exciting time in our industry: colleges professors influenced by Steve Yegge are holding lectures."

Other passages in the Adams interview stood out to me. When he shared his intention to become a professional photographer, instead of a concert pianist:

Some friends said, "Oh, don't give up music. ... A camera cannot express the human soul." The only argument I had for that was that maybe the camera couldn't, but I might try through the camera.

What a wonderful response. Many programmers feel this way about their code. CS attracts a lot of music students, either during their undergrad studies or after they have spent a few years in the music world. I think this is one reason: they see another way to create beauty. Good news for them: their music experience often gives them an advantage over those who don't have it. Adams believed that studying music was valuable to him as a photographer:

How has music affected your life?

Well, in music you have this absolutely necessary discipline from the very beginning. And you are constructing various shapes and controlling values. Your notes have to be accurate or else there's no use playing. There's no casual approximation.

Discipline. Creation and control. Accuracy and precision. Being close isn't good enough. That sounds a lot like programming to me!


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

August 13, 2011 2:47 PM

Trust People, Not Technology

Another of the interviews I've read recently was The Rolling Stone's 1994 interview with Steve Jobs, when he was still at NeXT. This interview starts slowly but gets better as it goes on. The best parts are about people, not about technology. Consider this, on the source Jobs' optimism:

Do you still have as much faith in technology today as you did when you started out 20 years ago?

Oh, sure. It's not a faith in technology. It's faith in people.

Explain that.

Technology is nothing. What's important is that you have a faith in people, that they're basically good and smart, and if you give them tools, they'll do wonderful things with them. It's not the tools that you have faith in -- tools are just tools. They work, or they don't work. It's people you have faith in or not.

I think this is a basic attitude held by many CS teachers, about both technology and about the most important set of people we work with: students. Give them tools, and they will do wonderful things with them. Expose them to ideas -- intellectual tools -- and they will do wonderful things. This mentality drives me forward in much the same way as Jobs's optimism does about the people he wants to use Apple's tools.

I also think that this is an essential attitude when you work as part of a software development team. You can have all the cool build, test, development, and debugging tools money can buy, but in the end you are trusting people, not technology.

Then, on people from a different angle:

Are you uncomfortable with your status as a celebrity in Silicon Valley?

I think of it as my well-known twin brother. It's not me. Because otherwise, you go crazy. You read some negative article some idiot writes about you -- you just can't take it too personally. But then that teaches you not to take the really great ones too personally either. People like symbols, and they write about symbols.

I don't have to deal with celebrity status in Silicon Valley or anywhere else. I do get to read reviews of my work, though. Every three years, the faculty of my department evaluate my performance as part of the dean's review of my work and his decision to consider for me another term. I went through my second such review last winter. And, of course, frequent readers here have seen my comments on student assessments, which we do at the end of each semester. I wrote about assessments of my spring Intelligent Systems course back in May. Despite my twice annual therapy sessions in the form of blog entries, I have a pretty good handle on these reviews, both intellectually and emotionally. Yet there is something visceral about reading even one negative comment that never quite goes away. Guys like Jobs probably do there best not to read newspaper articles and unsolicited third-party evals.

I'll have to try the twin brother gambit next semester. My favorite lesson from Jobs's answer, though, is the second part: While you learn to steel yourself against bad reviews, you learn not to take the really great ones too personally, either. Outliers is outliers. As Kipling said, all people should count with you, but none too much. The key in these evaluations to gather information and use it to improve your performance. And that most always comes out of the middle of the curve. Treating raves and rants alike with equanimity keeps you humble and sane.

Ultimately, I think one's stance toward what others say comes back to the critical element in the first passage from Jobs: trust. If you trust people, then you can train yourself to accept reviews as a source of valuable information. If you don't, then the best you can do is ignore the feedback you receive; the worst is that you'll damage your psyche every time you read them. I'm fortunate to work in a department where I can trust. And, like Jobs, I have a surprising faith in my students' fairness and honesty. It took a few years to develop that trust and, once I did, teaching came to feel much safer.


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

August 12, 2011 8:45 PM

"Always Stop When You Know What Is Going To Happen Next"

A few weeks ago, I ran across an article that quoted from published interviews with nine creative people. Over the last couple of days, I have been reading the original interviews that most interested me. Three in particular jogged my mind about creativity, art, and the making of things -- all of which are a part of how I view craft as a programmer and teacher.

Who would have thought that an interview with author Ernest Hemingway in The Paris Review's "The Art of Fiction No. 21" would make me think about computer programming and test-driven development? But it did. When asked about his writing schedule, Hemingway described a morning habit that I myself enjoy:

When I am working on a book or a story I write every morning as soon after first light as possible. There is no one to disturb you and it is cool or cold and you come to your work and warm as you write. You read what you have written and, as you always stop when you know what is going to happen next, you go on from there. You write until you come to a place where you still have your juice and know what will happen next and you stop and try to live through until the next day when you hit it again. You have started at six in the morning, say, and may go on until noon or be through before that. When you stop you are as empty, and at the same time never empty but filling, as when you have made love to someone you love. Nothing can hurt you, nothing can happen, nothing means anything until the next day when you do it again. It is the wait until the next day that is hard to get through.

I love this paragraph. While discussing mundane details of how he starts his writing day, Hemingway seamlessly shifts into a simile comparing writing -- and stopping -- to making love. Writers and other artists can say such things and simply be viewed for what they are: artists. I dare say many computer programmers feel exactly the same about writing programs. Many times I have experienced the strange coincident feelings of emptiness and fullness after a long day or night coding, and the longing to begin again tomorrow. Yet I knew, as Hemingway did, that the breaks were a necessary part of the discipline one needed to write well and consistently over the long haul. (Think sustainable pace, my friends.)

Yet, if one of us programmers were to say what Hemingway said above, to compare the feeling we have when we stop programming to the the feeling we have after making love to a person we love, most people would have to fight back a smirk and suppress an urge to joke about nerds never having sex and not being able to get girls (or guys). The impolite among them would say it out loud. If you are careful in choosing your friends and perhaps a bit lucky, you will surround yourself with friends who react to you saying this with a sympathetic nod, because they know that you, too, are a writer, and something of an artist.

On a more practical note, the writing habit Hemingway describes resembles a habit many of us programmers have. In the world of TDD, you will often hear people say, "Stop at the end of the day with a failing test." My friend, poet and programmer Richard Gabriel, has spoken of ending the day in the middle of a line of code. Both ideas echo Hemingway's advice, because they leave us in the same great position the next morning: ready to start the day by doing something obvious, something concrete.

But why is that so important?

But are there times when the inspiration isn't there at all?

Naturally. But if you stopped when you knew what would happen next, you can go on. As long as you can start, you are all right. The juice will come.

Writing is hard. Starting is hard. But if you are a writer, you must write, you must start. Likewise a programmer. As many people will tell you, inspiration is a fickle and overrated gift. Hemingway speaks elsewhere in the interview of days filled with inspiration, but they are rare. The writer writes regardless of inspiration. In writing, one often creates the very inspiration he seeks.

As long as you can start, you are all right.

Later in the piece, Hemingway has something to interesting to say about a different sort of starting: starting a career. When asked if financial security can be a detriment to good writing, he says:

If it came early enough and you loved life as much as you loved your work it would take much character to resist the temptations. Once writing has become your major vice and greatest pleasure only death can stop it. Financial security then is a great help as it keeps you from worrying. Worry destroys the ability to write. [Worry] attacks your subconscious and destroys your reserves.

This made me think of young CS grads in start-up companies, working to get by on a minimal budget while fulfilling a passion to make something. Being poor may not be as good for our souls as some would have us think, but it does inoculate us from temptations available to us only if we have resources. Once programming is your habit -- "your major vice and greatest pleasure" -- then you are on the path for a productive life as a programmer. If financial success comes too early, or if you are born with resources, you can still become a programmer, but you may have too battle the attraction of things that will get in the way of the work necessary to develop your craft.

This is one of the motives behind the grueling 6-year trial to which we subject new profs to in our universities: to instill habits of work and thought before they receive the temptation-heavy mantle of tenure. Unlike Hemingway's prescription, though, at most research schools the tenure-track phase usually includes an unhealthy dose of uncertainty and worry. But then again, maybe being a poor, struggling young writer or artist does, too.

That's one reason I like Hemingway's answer so much. He does not romanticize being poor. He acknowledges that, once one has the habit of writing, financial security can be a great benefit, because it relieves the writer of the stress that can kill her productivity.

Despite enjoying these insightful passages so much, I cannot say that this a great interview. Hemingway is too often unwilling to talk about elements of the the craft of writing, and he expends too many words telling interviewer George Plimpton -- an intelligent man and accomplished journalist himself -- that his questions are cliche, worn, or stupid. Still, I was driven to read through to the end, and I enjoyed it.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

August 11, 2011 7:59 PM

Methods, Names, and Assumptions in Adding New Code to a Program

Since the mid-1990s, there has been a healthy conversation around refactoring, the restructuring of code to improve its internal structure without changing its external behavior. Thanks to Martin Fowler, we have a catalog of techniques for refactoring that help us restructure code safely and reliably. It is a wonderful tool for learners and practitioners alike.

When it comes to writing new code, we are not so lucky. Most of us learn to program by learning to write new code, yet we rarely learn techniques for adding code to a program in a way that is as safe and reliable as effective as the refactorings we know and love.

You might think that adding code would be relatively simple, at least compared to restructuring a large, interconnected web of components. But how can we move with the same confidence when adding code as we do when we follow a meticulous refactoring recipe under the protection of good unit tests permits? Test-driven design is a help, but I have never felt like I had the same sort of support writing new code as when I refactor.

So I was quite happy a couple of months ago to run across J.B. Rainsberger's Adding Behavior with Confidence. Very, very nice! I only wish I had read it a couple of months ago when I first saw the link. Don't make the same mistake; read it now.

Rainsberger gives a four-step process that works well for him:

  1. Identify an assumption that the new behavior needs to break.
  2. Find the code that implements that assumption.
  3. Extract that code into a method whose name represents the generalisation you're about to make.
  4. Enhance the extracted method to include the generalisation.

I was first drawn to the idea that a key step in adding new behavior is to make a new method, procedure, or function. This is one of the basic skills of computer programming. It is one of the earliest topics covered in many CS1 courses, and it should be taught sooner in many others.

Even still, most beginners seem to fear creating new methods. Even more advanced students will regress a bit when learning a new language, especially one that works differently than the languages they know well. A function call introduces a new point of failure: parameter passing. When worried about succeeding, students generally try to minimize the number of potential points of failure.

Notice, though, that Rainsberger starts not with a brand new method, empty except for the new code to be written. This technique asks us first to factor out existing code into a new method. This breaks the job of writing the new code into two, smaller steps: First refactor, relying on a well-known technique and the existing tests to provide safety. Second, add the new code. (These are Steps 3 and 4 in Rainsberger's technique.)

That isn't what really grabbed my attention first, however. The real beauty for me is that extracting a method forces us to give it us a name. I think that naming gives us great power, and not just in programming. A lot of times, CS textbooks make a deal about procedures as a form of abstraction, and they are. But that often feels so abstract... For programmers, especially beginners, we might better focus on the fact that help us to name things in our programs. Names, we get.

By naming a procedure that contains a few lines of code, we get to say what the code does. Even the best factored code that uses good variable names tends to say how something is done, not what it is doing. Creating and calling a method separates the two: the client does what the method does, and the server implements how it is done. This separation gives us new power: to refactor the code in other ways, certainly. Rainsberger reminds us that it also gives us power to add code more reliably!

"How can I add code to a program? Write a new function." This is an unsurprising, unhelpful answer most of the time, especially for novices who just see this as begging the question. "Okay, but what do I do then?" Rainsberger makes it a helpful answer, if a bit surprising. But he also puts it in a context with more support, what to do before we start writing the new code.

Creating and naming procedures was the strongest take-home point for me when I first read this article. As the ideas steeped in my mind for a few days, I began to have a greater appreciation for Rainsberger's focus on assumptions. Novice thinkers have trouble with assumptions. This is true whether they are learning to program, learning to read and analyze literature, or learning to understand and argue public policy issues. They have a hard time seeing assumptions, both the ones they make and the ones made by other writers. When the assumptions are pointed out, they are often unsure what to do with them, and are tempted to skip right over them. Assumptions are easy to ignore sometimes, because they are implicit and thus easy to lose track of when deep in a argument.

Learning to understand and reason about assumptions is another important step on the way to mature thinking. In CS courses, we often introduce the idea of preconditions and postconditions in Data Structures. (Students also see them in a discrete structures course, but there they tend to be presented as mathematical tools. Many students dismiss their value out of hand). Writing pre- and postconditions for a method is a way to make assumptions in your program explicit. Unfortunately, most beginning don't yet see the value in writing them. They feel like an extra, unnecessary step in a process dominated by the uncertainty they feel about their code. Assuring them that these invariants help is usually like pushing a rock up a hill. Tomorrow, you get to do it again.

One thing I like about Rainsberger's article is that it puts assumptions into the context of a larger process aimed at helping us write code more safely. Mathematical reasoning about code does that, too, but again, students often see it as something apart from the task of programming. Rainsberger's approach is undeniably about code. This technique may encourage programmers to begin thinking about assumptions sooner, more often, and more seriously.

As I said, I haven't seen many articles or books talk about adding code to a program in quite this way. Back in January, "Uncle Bob" Martin wrote an article in the same spirit as this, called The Transformation Priority Premise. It offers a grander vision, a speculative framework for all additions to code. If you know Uncle Bob's teachings about TDD, this article will seem familiar; it fits quite nicely with the mentality he encourages when using tests to drive the growth of a program. While his article is more speculative, it seems worthy or more thought. It encourages the tiniest of steps as each new test provokes new code in our program. Unfortunately, it takes such small steps that I fear I'd have trouble getting my students, especially the novices, to give it a fair try. I have a hard enough time getting most students to grok the value of TDD, even my seniors!

I have similar concerns about Rainsberger's technique, but his pragmatism and unabashed focus on code gibes me hope that it may be useful teaching students how to add functionality to their programs.


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

July 06, 2011 12:23 PM

Don't Forget Your 3000-LOC Check-Up!

Yesterday, Michael Feathers tweeted:

If a code base is more complicated than a car, shouldn't it have a maintenance plan too?

I asked him, "Refactoring every 3K miles?", and he joked back, "Well, maybe every 3K lines." I had thought about using LOC in my tweet decided to stick with the auto analogy. Whatever its weaknesses, LOC seems to be the first place programmers' minds go when we talk about the volume of code. (Though, as much traveling as Feathers and other big-time consultants and speakers do in a year, maybe 3000 miles is the right magnitude after all.)

Feathers makes a serious point, even if he didn't mean it too seriously. When we buy a car, we implicitly accept the notion of scheduled maintenance: change the oil every so often; have the engine tuned up every so often; replace the battery and rotate the tires every so often. We accept it because we know that it makes our car run better and last longer.

When we buy software, we want it to run forever, as is. Or the company who sells it to us wants us to run it as-is forever -- or buy a new version. Imagine having to buy a new car as soon as your current car started coughing, wheezing, or seizing up on dirty oil.

I mentioned refactoring in my joke because it is part of the maintenance plan built in to XP and used in so many agile approaches to software development. XP discourages long-form maintenance in the form of refactoring every few months or even weeks. Instead, it encourages a sort of continuous maintenance, in a tight test-code-refactor cycle. It's kind of like checking your car's oil, fluids, tires, etc., after every use.

When we do that to a car, it's usually because the car is in bad shape, breaking down as we try to extend its life. But continuous refactoring of a code base is usually a sign of robust health. It means that we know our code is in good shape and ready for use -- and extension. Teams that maintain their code on automobile-like time scales are usually sitting on a time bomb. Users may be able to use the code, but the programmers dare not touch its internals.

My other thought as I tweeted was about our inability, or perhaps unwillingness, to make this idea come alive for the students in our university CS programs.

It is an inability because it is so hard to create ways for students to live with any body of code longer than a semester or two, and time is a necessary ingredient facing the need for maintenance. Of all my project courses, compilers seems the most frequent teacher of this lesson. A semester may not be long, but a compiler is complex enough, and a non-trivial language spec hard enough to understand, to accelerate the sense of age and deterioration.

It is perhaps an unwillingness because most every CS faculty I know makes very little effort to change courses and degree programs to make this lesson approachable. The good news is that making changes to bring this idea within our students' learning horizons also brings a lot of other important software development lessons within their horizons.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

June 27, 2011 5:03 PM

"You can code. That is pretty damn cool."

I've been off-line a lot lately, doing physical therapy for my knee and traveling a bit. That means I have a lot of fun reading to catch up on! One page that made the rounds recently is Advice From An Old Programmer, from Zed Shaw's intro book, Learn Python The Hard Way. Shaw has always been a thoughtful developer and an entertaining writer with a unique take on programming. Now he has put his money where his mouth is with a book that aims to teach programming in a style he thinks most effective for learners.

I look forward to digging into the book soon, but for now his advice page has piqued a lot of interest. For example:

Programming as a profession is only moderately interesting. It can be a good job, but you could make about the same money and be happier running a fast food joint. You're much better off using code as your secret weapon in another profession.

As a matter of personal opinion, I disagree with the first sentence, and could never make the switch discussed in the second. But I do think that the idea of programming as a secret weapon in other professions has a lot to offer people who would never want to be computer scientists or full-time software developers. It's a powerful tool that frees you from wishing you have a programmer around. It changes how you can think about problems in your discipline and lets you ask new questions.

Finally, Shaw tells his readers not too worry when non-programmers treat them badly because they are now nerds who can program. He gives good reasons why you shouldn't care about such taunts, and then sums it up in a Zed Shaw-like killer closing line:

You can code. They cannot. That is pretty damn cool.

Amen.


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

June 15, 2011 7:53 AM

Barbarians at the Agile Gate

For the last year or so, there seems to have been something of a backlash against agile software development. A lot of conference speakers and bloggers have been telling us about the failures of the move to agile approaches, both the misconceptions at its base and the misdirections in its evolution. I have been especially uncomfortable watching writers and consultants who have teaching the world the ways of agile development join the bandwagon.

Don't get me wrong. I am aware that agile development has its weaknesses; all things do. I'm also aware that the social and technical movement leading to its adoption across our industry has had its problems; all movements do. I do believe that we should understand the weaknesses in our practices and our methods for teaching the world about them, so that we can learn how to do those things better. Still, it's been a little disconcerting to watch the backlash proceed.

Then again, in my short career, I've seen something similar happen to design patterns, object-oriented programming, and structured programming. It seems the natural order of history in our business. I've long wondered why.

Then I came across The Return of the Barbarian, which tells the story of humans history as a cycle between barbarian culture and civilization. If we think of the software world in similar terms, our own history makes sense. Agile software development was once the barbarian. Now its the civilized culture, ripe to be conquered by a new, hungry barbarian.

How so? Think back to before the days of agile. The software world, broadly speaking, had an entrenched culture that we all recognize. Developers and clients were different breeds. Developers and users, too. We documented stable requirements, designed up front a software system to deliver them, and passed the design onto programmers, wrote code. When the process didn't go as well as planned, programmers worked longer and harder to meet their deadlines. This was an idealized world, to be sure, but we strove hard to meet the ideal. People who had made this style of development work -- smart people, energetic people -- codified their knowledge in textbooks and training courses, so that the rest of us could learn how to duplicate their successes. Anyone willing to study could learn the techniques and become part of civilized society.

Collectively, we were wise, but individually, we were weak, really, going through the motions.

Along came agile. It turns out that there were world-class developers -- smart people, energetic people -- who did things differently. They worked closely with their clients and users. They collaborated heavily among themselves. They took small steps, refactored their code, and grew their software, rather than erecting it. To many in the industry, this was a romantic way to live and work, and they wanted to join in the fun.

The dominant software culture didn't see it that way, though. Agile looked, well, barbaric. What happens when a cowboy programmer does something to break the system? How can we write programs if we don't know everything about what it should do? Where are the systematic controls on the process? Those entrenched in civilized software development culture saw agile methods as a step backward, to a less advanced time. But they were wrong, as we read in "The Return of the Barbarian":

The reason this seems like a strange phenomenon is that we confuse refinement with advancement. Finely-crafted jewelry is not more advanced than roughly-hewn jewelry. A Boeing 747 is about a million times more capable than the Wright Flyer I, but it does not contain a million times as much intelligence. It is merely more refined.... The difference between advancement and refinement is clearest in disruption. A beautifully-crafted sword is not more advanced than a crude gun. It is merely more refined.

The problem was, the software civilization built around structured programming was more than refined than the agile approaches, but not necessarily more advanced. The system itself was quite intelligent, with much wisdom and knowledge encoded in its practices, its textbooks, and its other literature. But individually, developers did not need to be as sharp, because the system guided them to success (as much as it could).

The above passage is soon followed by a stark distinction:

The intelligence manifest in an artifact is simply the amount of human thought that has been externalized into it. Refinement on the other hand, is a measure of the amount of work that has gone into it. In Hegelian terms, intelligence in design is fundamentally a predatory quality put in by barbarian-Masters. Refinement in design is a non-predatory quality put in by civilized-Slaves.

It was in this context that agile -- a new barbarian culture -- swooped in and made inroads. The existing culture derided it as a fad, but it was in fact a set of advanced values, principles, and practices, less polished than the refined extant culture but full of deep thought and human experience.

Over time, we saw the inevitable cultural evolution. In order to teach agile values, principles, and practices to a wider audience, barbarian-masters wrote down their wisdom in the form of books and conference talks and podcasts and index cards. In order to reach the managerial class of the corporations that build and buy software, first- and second- generation agilista created management seminars and certification programs and the trappings of institutional respectability. The practices were packaged, adjusted... refined. Soon everyone could "do" agile, or at least pretend to, by following the rules. Some folks got it, though not everyone, but most everyone tried to do it.

The agile barbarian has become the civilized Organization Man. Where is the romance in that?

Now new barbarians are at the gate, ready to shove the once-romantic revolutionaries of OO and patterns and agile development out into the streets. It is the natural order.

Here's the thing. Agile approaches still work as well as they did back when they were the knowledge in the minds of great programmers, who were unhindered by the rules that they follow instinctively and break when necessary in the pursuit of a great program. That knowledge was born out of experience and embodied wisdom gained from living in the civilization that came before.

If we want to become like the agile masters, we need to do more than imitate them. We need to live the values, principles, and practices -- to make them our own, not something written in a book or a blog.

Perhaps this is just a fanciful retelling of our history to explain away the agile movement's shortcomings and failures. But I think it carries a grain of truth. A new barbarian knocks down the door as soon as we become too civilized, when we convert our deep, compiled, pragmatic, contextual knowledge into handbooks and notecards and consultants' packaged talks and on-site training courses.

To the extent that my tale is true, I think it offers us a path forward: a reminder to embrace our barbarian past. Each of us can develop his or her own individual intelligence, rather than relying on the external trappings of a civilized movement. Don't let the next revolution cause you to abandon what works well. Look for useful knowledge and practice in the ways of the next wave of barbarians, and use it to get better.

Instead of arguing with others about test-first design, pair programming and refactoring, about collaboration with users, collective code ownership, and sustainable pace, we should simply do them, in the way that fits best our context. This leads by example. It may not scale as fast as the civilized approach, but as we have seen, that approach is fraught with its own dangers.

Besides, the goal isn't to scale or to create a movement. It's to write great programs.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

May 23, 2011 2:34 PM

Plan A Versus Plan B

Late last week, Michael Nielsen tweeted:

"The most successful people are those who are good at Plan B." -- James Yorke

This is one of my personal challenges. I am a pretty good Plan A person. Historically, though, I am a mediocre Plan B person. This is true of creating Plan B, but more importantly of recognizing and accepting the need for Plan B.

Great athletes are good at Plan B. My favorite Plan B from the sporting world was executed by Muhammad Ali in the Rumble in the Jungle, his heavyweight title fight against George Foreman in October 1974. Ali was regarded by most at that time as the best boxer in the world, but in Foreman he encountered a puncher of immense power. At the end of Round 1, Ali realized that his initial plan of attacking Foreman was unlikely to succeed, because Foreman was also a quick fighter who had begun to figure out Ali's moves. So Ali changed plans, taking on greater short-term risk by allowing Foreman to hit him as much as he wanted, so long as the blows were not the kind likely to end the fight immediately. Over the next few rounds, Foreman began to wear down, unaccustomed to throwing so many punches for so many rounds against an opponent who did not weaken. Eventually, Ali found his opening, attacked, and ended the fight in Round 8.

This fight is burned in my mind for the all-time great Plan B moment: Ali sitting on his stool between the first and second rounds, eyes as wide and white as platters. I do not ever recall seeing fear in Muhammad Ali's eyes at any other time in his career, before or after this fight. He believed that Foreman could knock him out. But rather than succumb to the fear, he gathered himself, recalculated, and fought a different fight. Plan B. The Greatest indeed.

Crazy software developer that I am, I see seeds of Plan B thinking in agile approaches. Keep Plan A simple, so that you don't overcommit. Accept Plan B as a matter of course, refactoring in each cycle to build what you learn from writing the code back into the program. React to your pair's ideas and to changes in the requirements with aplomb.

There is good news: We can learn how to be better at Plan B. It takes effort and discipline, just as changing any of our habits does. For me, it is worth the effort.

~~~~

If you would like to learn more about the Rumble in the Jungle, I strongly recommend the documentary film When We Were Kings, which tells the story of this fight and how it came to be. Excellent sport. excellent art, and you can see Ali's Plan B moment with your own eyes.


Posted by Eugene Wallingford | Permalink | Categories: General, Personal, Software Development

May 20, 2011 11:55 AM

Learning From Others

I've been reading through some of the back entries in Vivek Haldar's blog and came across the entry Coding Blind. Haldar notes that most professionals and craftsmen learn their trade at least in part by watching others work, but that's not how programmers learn. He says that if carpenters learned the way programmers do, they'd learn the theory of how to hammer nails in a classroom and then do it for the rest of their careers, with every other carpenter working in a different room.

Programmers these days have a web full of open-source code to study, but that's not the same. Reading a novel doesn't give you any feel at all for what writing a novel is like, and the same is true for programming. Most CS instructors realize this early in their careers: showing students a good program shows them what a finished program looks like, but it doesn't give them any feel at all for what writing a program is like. In particular, most students are not ready for the false starts and the rewriting that even simple problems will cause them.

Many programming instructors try to bridge this gap by writing code live in class, perhaps with student participation, so that students can experience some of the trials of programming in a less intimidating setting. This is, of course, not a perfect model; instructors tend not to make the same kind of errors as beginners, or as many, but it does have some value.

Haldar points out one way that other kinds of writers learn from their compatriots:

Great artists and writers often leave behind a large amount of work exhaust other than their finished masterpieces: notebooks, sketches, letters and journals. These auxiliary work products are as important as the finished item in understanding them and their work.

He then says, "But in programming, all that is shunned." This made me chuckle, because I recently wrote a bit about my experience having students maintain engineering notebooks for our Intelligent Systems course. I do this so that they have a record of their thoughts, a place to dump ideas and think out loud. It's an exercise in "writing to learn", but Haldar's essay makes me think of another potential use of the notebooks: for other students to read and learn from. Given how reluctant my students were to write at all, I suspect that they would be even more reluctant to share their imperfect thoughts with others in the course. Still, perhaps I can find a way to marry these ideas.

cover of rpg's Writers' Workshops

This makes me think of another way that writers learn from each other, writers' workshops. Code reviews are a standard practice in software, and PLoP, the Pattern Languages of Programs conference, has adapted the writers' workshop form for technical writers. One of the reasons I like to teach certain project courses in a studio format is that it gives all then teams an opportunity to see each other's work and to talk about design, coding, and anything else that challenges or excites them. Some semesters, it works better than others.

Of course, a software team itself has the ability to help its members learn from one another. One thing I noticed more this semester than in the past was students commenting that they had learned from their teammates by watching them work. Some of the students who said this viewed themselves as the weakest links on their teams and so saw this as a chance to approach their more accomplished teammates' level. Others thought of themselves as equals to their teammates yet still found themselves learning from how others tackled problems or approached learning a new API. This is a team project succeeding as we faculty hope it might.

Distilling experience with techniques in more than just a finished example or two is one of the motivations for the software patterns community. It's one of the reasons I felt so comfortable with both the literary form and the community: its investment in and commitment to learning from others' practice. That doesn't operate at quite the fundamental level of watching another carpenter drive a nail, but it does strike close to the heart of the matter.


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

May 13, 2011 2:26 PM

Patterns for Naming Things

J.B. Rainsberger's short entry grabbed my attention immediately. I think that Rainsberger is talking about a pair of complementary patterns that all developers learn at some point or other as they write more and bigger programs. He elegantly captures the key ideas in only a few words.

These patterns balance common forces between giving things long names and giving things short names. A long name can convey more information, but a short name is easier to type, format, and read. A long name can be a code smell that indicates a missing abstraction, but a short name can be a code smell that indicates premature generalization, a strange kind of YAGNI violation.

The patterns differ in the contexts in which they appear successfully. Long names are most useful the first time or two you implement an idea. At that point, there are few or no other examples of the idea in our code, so there is not yet a need for an abstraction. A long name can convey valuable information about the idea. As an idea appears more often, two or more long names will begin to overlap, which is a form of duplication. We are now ready to factor out the abstraction common to them. Now the abstraction conveys some or all of the information and short names become more valuable.

I need to incorporate these into any elementary pattern language I document, as well as in the foundation patterns layer of any professional pattern language. One thing I would like to think more about is how these patterns relate to Kent Beck's patterns Intention-Revealing Name and Type-Revealing Name.


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

May 12, 2011 10:18 AM

What Students Said

Curly says, 'one thing'

On the last day of my Intelligent Systems course, I asked my students three retrospective questions. Each question asked them to identify one thing...

  • one thing you learned about AI by doing this project
  • one thing you learned about writing software by doing this project
  • one thing that makes your program "intelligent"

Question 3 is a topic for another day, when I will talk a bit about AI. Today I am thinking more about what students learned about writing software. As one of our curriculum's designated "project courses", Intelligent Systems has the goal of giving students an experience building a significant piece of software, as part of a team. What do the students themselves think they learned?

A couple of answers to the first question were of more general software development interest:

I learned that some concepts are easy to understand conceptually but difficult to implement or actually use.

I learned to be open-minded about several approaches to solving a problem. ... be prepared to accept that an approach might take a lot of time to understand and end up being [unsuitable].

There is nothing like trying to solve a real problem to teach you how hard some solutions are to implement. Neural networks were the most frequently mentioned concept that is easy to understand but hard to make work in practice. Many students come out their AI course thinking neural nets are magic; it turns out magic can be hard to serve up. I suspect this is true of many algorithms and techniques students learn over the course of their studies.

I don't recall talking about agile software development much during this course, though no doubt it leaks out in how I typically talk about writing software. Still, I was surprised at the theme running through student responses to the second question.

For example:

Design takes time. Multiple iterations, revise and test.

A couple of teams discovered spike solutions, sorta:

You may write a lot of worthless or bad code to help with the final solution. We produced a lot of bad code that was never used in the end product, but it helped us get to that point.

These weren't true spikes, because the teams didn't set out with the intention of using the code to learn. But most didn't realize that they could or should do this. Now that they know, they might behave differently in the future. Most important, they learned that it's okay to "code to learn".

Many students came to appreciate collective code ownership and tools that support it:

When writing software in a group, it is important to make your code readable: descriptive [names] and comments that describe what is going on.

I learned how to maintain a project with a repository so that each team member can keep his copy up-to-date. ... I also learned how to use testing suites.

Tests also showed up in one of my favorite student comments, about refactoring:

I learned that when refactoring even small code you need unit tests to make sure you are doing things correctly. Brute forcing only gets you into trouble and hours of debugging bad code.

Large, semester-long projects usually given students their first opportunity to experience refactoring. Living inside a code base for a while teaches them a lot about what software development is really like, especially code they themselves have written. Many are willing to accept that living with someone else's code can be difficult but believe that their own code will be fine. Turns out it's not. Most students then come to appreciate the value of refactoring techniques I need to help them learn refactoring tools better.

Finally, this comment from the first student retrospective I read captures a theme I saw throughout:

It is best to start off simple and make something work, rather than trying to solve the entire problem at once and get lost in its complexity.

This is in many ways the heart of agile software development and the source for all the other practices we find so useful. Whatever practices my own students adopt in the coming years, I hope they are guided by this idea.

~~~~

Some of you will recognize the character in the image above as Curly, the philosopher-cowboy from City Slickers. One of the great passages of that 1991 film has Curly teaching protagonist Mitch about the secret of life, "One thing. Just one thing."

I am not the first software person to use Curly as inspiration. Check out, for example, Curly's Law: Do One Thing. Atwood shows how "do one thing" is central to "several core principles of modern software development.


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

May 10, 2011 4:32 PM

Course Post-Mortem and Project Notebooks

I'm pretty much done with my grading for the semester. All that's left is freezing the grades and submitting them.

Intelligent Systems is a project course, and I have students evaluate their and their teammates' contributions to the project. One part of the evaluation is to allocate the points their team earns on the project to the team members according to the quality and quantity of their respective contributions. As I mentioned to the class earlier in the semester, point allocations from semester to semester tend to exhibit certain features. With few exceptions:

  • Students are remarkably generous to one another, as long as the teammate makes a reasonable effort under the circumstances.
  • If anything, students tend to undervalue their own contribution.
  • The allocations are remarkably consistent across teammates on the same team.
  • The allocations are remarkably consistent with what I would assign, based on my interactions with the team over the course of the project.

All that adds up to me being rather satisfied with the grades that fall out of the grinder at the end of the semester.

One thing that has not changed since I last taught this course ten years ago or so is that most students don't like the idea of an engineer's notebook. I ask each student to maintain a record their of their notes while working on the project along with a weekly log intended to be a periodic retrospective of their work and progress, their team's work and progress, and the problems they encounter and solve along the way. Students have never liked keeping notebooks. Writing doesn't seem to be a habit we develop in our majors, and by the time they reach their last ultimate or penultimate semester, the habit of not writing is deeply ingrained.

One thing that may have changed in the last decade: students seem more surly at being asked to keep a notebook. In the past, students either did write or didn't write. This year, for the most part, students either didn't write or didn't write much except to say how much they didn't like being asked to write. I have to admire their honesty at the risk of being graded more harshly for having spoken up. (Actually, I am proud they trust me enough to still grade them fairly!) I can't draw a sound conclusion from one semester's worth of data, but I will watch for a trend in future semesters.

One thing that did change this semester: I allowed students to blog instead of maintaining a paper notebook. I was surprised that only two students took me up on the offer. Both ended up with records well above the average for the class. One of the students treated his blog a bit more formally than I think of an engineer's notebook, but the other seemed to treat much as he would have a paper journal. This was a win, one I hope to replicate in the future.

The Greeks long ago recorded that old habits die hard, if at all. In the future, I will have to approach the notebook differently, including more and perhaps more persuasive arguments for it up front and more frequent evaluation and feedback during the term. I might even encourage or require students to blog. This is 2011, after all.


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

May 05, 2011 3:35 PM

Reaching for Too Much, in Life and Software Development

I just read this passage from The Rhythm of Life, by Matthew Kelly:

You never can get enough of what you don't really need.

Fulfillment comes not from having more and more of everything forever into oblivion. Fulfillment comes from having what you need.

Kelly is talking about how we live our lives. However, I could not help but think of You Aren't Gonna Need It and agile software development.

From there, Kelly takes a moral turn, but even then I hear the agile voice within:

The whole world is chasing illegitimate wants with reckless abandon. We use all of our time, effort, and energy in the pursuit of our illegitimate wants, hypnotized by the lie that our illegitimate wants are the key to our happiness.

At the same time, the gentle voice within us is constantly calling out to us, trying to encourage us not to ignore the wisdom we already possess.

There is a lot to be said for learning to be content with implementing the features we are working on right now, not features we think are coming in the future. Perhaps if we can learn to be content in life we can also learn to be content in code.


Posted by Eugene Wallingford | Permalink | Categories: Personal, Software Development

May 03, 2011 4:26 PM

There Is No Normal

Part of what made diagnosing my knee injury challenging is that the injury has not presented normally. Normally, this condition follows an obvious trauma. I did not suffer one. Normally, the symptoms include occasional locking of the joint and occasionally feeling as if the joint is going to give out. I have not experienced either. Normally, there is more pain than I seem to be having.

The doctors were surprised by this unusual presentation, but it didn't worry them much. They are used to the fact that there is no normal.

The human body is a complex machine, and people subject their bodies to a complex set of stimuli and conditions. As a result, the body responds in an unbelievable number of ways. What we think of as the "normal" path of most diseases, injuries, and processes is a composite of many examples. Each symptom or observation has some likelihood of occurring, but it is common for a particular case to look quite unusual.

This is something we learn when we study statistical methods. It's possible that no number in a set is equal to the average of all the numbers in a set. It's possible that no member in a set is normal in the sense of sharing all the features that are common to most members.

A large software system is a complex machine, and people subject software to a complex set of stimuli and conditions. As a result, the software responds in a surprising number of ways. When we think of this from the perspective people as users, we realize just how important designing for usability, reliability, and robustness are.

Programmers are people who interact with software, too, and we subject our programs to a wide-ranging set of demands. When we think about "there is no normal" from this perspective, we better understand why it is so challenging to debug, extend, and maintain programs.

Our programs may not be as complex as the human body, and we try to design them rather than let them evolve unguided. But I think it's still useful to program with a mindset that there is no normal. That way, like my doctor, we can handle cases that seem unusual with aplomb.


Posted by Eugene Wallingford | Permalink | Categories: Personal, Software Development

May 02, 2011 3:52 PM

Thinking and Doing in the Digital Age

Last week, someone I follow tweeted this link in order to share this passage:

You will be newbie forever. Get good at the beginner mode, learning new programs, asking dumb questions, making stupid mistakes, soliciting help, and helping others with what you learn (the best way to learn yourself).

That blog entry is about inexorable change of technology in then modern world and how, if we want to succeed in this world, we need a mindset that accommodates change. We might even argue that we need a mindset that welcomes or seeks out change. To me, this is one of the more compelling reasons for us to broaden the common definition of the liberal arts to include computing and other digital forms of communication.

As much as I like the quoted passage, I liked a couple of others as much or more. Consider:

Understanding how a technology works is not necessary to use it well. We don't understand how biology works, but we still use wood well.

As we introduce computing and other digital media to more people, we need to balance teaching how to use new ideas and techniques and teaching underlying implementations. Some tools change how we work without us knowing how they work, or needing to know. It's easy for people like me to get so excited about, say, programming that we exaggerate its importance. Not everyone needs to program all the time.

Then again, consider this:

The proper response to a stupid technology is to make a better one yourself, just as the proper response to a stupid idea is not to outlaw it but to replace it with a better idea.

In the digital world as in the physical world, we are not limited by our tools. We can change how our tools work, through configuration files and scripts. We can make our own tools.

Finally, an aphorism that captures differences between how today's youth think about technology and how people my age often think (emphasis added):

Nobody has any idea of what a new invention will really be good for. To evaluate, don't think; try.

This has always been true of inventions. I doubt many people appreciated just how different the world would be after the creation of the automobile or the transistor. But with digital tools, the cost of trying things out has been driven so low, relative to the cost of trying things in the physical world, that the cost is effectively zero. In so many situations now, the net value of trying things exceeds the net value of thinking.

I know that sounds strange, and I certainly don't mean to say that we should all just stop thinking. That's the sort of misinterpretation too many people made of the tenets of extreme programming. But the simple fact is, thinking too much means waiting too long. While you are thinking -- waiting to start -- someone else is trying, learning faster, and doing things that matter.

I love this quote from Elisabeth Hendrickson, who reminded herself of the wisdom of "try; don't think" when creating her latest product:

... empirical evidence trumps speculation. Every. Single. Time.

The scientific method has been teaching us the value of empiricism over pure thought for a long time. In the digital world, the value is even more pronounced.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

April 21, 2011 8:10 PM

Agile Approaches and the Small

Seth Godin recently blogged on the economies of small:

I think we embraced scale as a goal when the economies of that scale were so obvious that we didn't even need to mention them. Now that it's so much easier to produce a product in the small and market a product in the small, and now that it's so beneficial to offer a service to just a few, with focus and attention, perhaps we need to rethink the very goal of scale.

Agile approaches to software development exploit the economies of small:

  • small promises
  • short cycles
  • small teams
  • small steps
  • small changes
  • continuous integration

Traditional software engineering, based as it is on an engineering metaphor, seems invested in traditional economies of scale. That was a natural result of the metaphor bust also the tools of the time. Back when hardware and software made it more difficult to write software rapidly over short iterations, scale in the traditional sense -- large -- helped to make processes and maybe even people more efficient.

Things have changed.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

April 19, 2011 6:04 PM

A New Blog on Patterns of Functional Programming

(... or, as my brother likes to say about re-runs, "Hey, it's new to me.")

I was excited this week to find, via my Twitter feed, a new blog on functional programming patterns by Jeremy Gibbons, especially an entry on recursion patterns. I've written about recursion patterns, too, though in a different context and for a different audience. Still, the two pieces are about a common phenomenon that occurs in functional programs.

I poked around the blog a bit and soon ran across articles such as Lenses are the Coalgebras for the Costate Comonad. I began to fear that the patterns on this blog would not be able to help the world come to functional programming in the way that the Gang of Four book helped the world come to object-oriented programming. As difficult as the GoF book was for every-day programmers to grok, it eventually taught them much about OO design and helped to make OO programming mainstream. Articles about coalgebras and the costate comonad are certainly of value, but I suspect they will be most valuable to an audience that is already savvy about functional programming. They aren't likely to reach every-day programmers in a deep way or help them learn The Functional Way.

But then I stumbled across an article that explains OO design patterns as higher-order datatype-generic programs. Gibbons didn't stop with the formalism. He writes:

Of course, I admit that "capturing the code parts of a pattern" is not the same as capturing the pattern itself. There is more to the pattern than just the code; the "prose, pictures, and prototypes" form an important part of the story, and are not captured in a HODGP representation of the pattern. So the HODGP isn't a replacement for the pattern.

This is one of the few times that I've seen an FP expert speak favorably about the idea that a design pattern is more than just the code that can be abstracted away via a macro or a type class. My hope rebounds!

There is work to be done in the space of design patterns of functional programming. I look forward to reading Gibbons's blog as he reports on his work in that space.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Patterns, Software Development

April 14, 2011 10:20 PM

Al Aho, Teaching Compiler Construction, and Computational Thinking

Last year I blogged about Al Aho's talk at SIGCSE 2010. Today he gave a major annual address sponsored by the CS department at Iowa State University, one of our sister schools. When former student and current ISU lecturer Chris Johnson encouraged me to attend, I decided to drive over for the day to hear the lecture and to visit with Chris.

Aho delivered a lecture substantially the same as his SIGCSE talk. One major difference was that he repackaged it in the context of computational thinking. First, he defined computational thinking as the thought processes involved in formulating problems so that their solutions can be expressed as algorithms and computational steps. Then he suggested that designing and implementing a programming language is a good way to learn computational thinking.

With the talk so similar to the one I heard last year, I listened most closely for additions and changes. Here are some of the points that stood out for me this time around, including some repeated points:

  • One of the key elements for students when designing a domain-specific language is to exploit domain regularities in a way that delivers expressiveness and performance.
  • Aho estimates that humans today rely on somewhere between 0.5 and 1.0 trillion lines of software. If we assume that the total cost associated with producing each line is $100, then we are talking about a most serious investment. I'm not sure where he found the $100/LOC number, but...
  • Awk contains a fast, efficient regular expression matcher. He showed a figure from the widely read Regular Expression Matching Can Be Simple And Fast, with a curve showing Awk's performance -- quite close to Thompson NFA curve from the paper. Algorithms and theory do matter.
  • It is so easy to generate compiler front ends these days using good tools in nearly every implementation language. This frees up time in his course for language design and documentation. This is a choice I struggle with every time I teach compilers. Our students don't have as strong a theory background as Aho's do when they take the course, and I think they benefit from rolling their own lexers and parsers by hand. But I'm tempted by what we could with the extra time, including processing a more compelling source language and better coverage of optimization and code generation.
  • An automated build system and a complete regression test suite are essential tools for compiler teams. As Aho emphasized in both talks, building a compiler is a serious exercise in software engineering. I still think it's one of the best SE exercises that undergrads can do.
  • The language for quantum looks cool, but I still don't understand it.

After the talk, someone asked Aho why he thought functional programming languages were becoming so popular. Aho's answer revealed that he, like any other person, has biases that cloud his views. Rather than answering the question, he talked about why most people don't use functional languages. Some brains are wired to understand FP, but most of us are wired for, and so prefer, imperative languages. I got the impression that he isn't a fan of FP and that he's glad to see it lose out in the social darwinian competition among languages.

If you'd like to see an answer to the question that was asked, you might start with Guy Steel's StrangeLoop 2010 talk. Soon after that talk, I speculated that documenting functional design patterns would help ease FPs into the mainstream.

I'm glad I took most of my day for this visit. The ISU CS department and chair Dr. Carl Chang graciously invited me to attend a dinner this evening in honor of Dr. Aho and the department's external advisory board. This gave me a chance to meet many ISU CS profs and to talk shop with a different group of colleagues. A nice treat.


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

April 12, 2011 7:55 PM

Commas, Refactoring, and Learning to Program

The most important topic in my Intelligent Systems class today was the comma. Over the last week or so, I had grading their essays on communicating the structure and intent of programs. I was not all that surprised to find that their thoughts on communicating the structure and intent of programs were not always reflected in their essays. Writing well takes practice, and these essays are for practice. But the thing that stood out most glaringly from most of the papers was the overuse, misuse, and occasional underuse of the comma. So after I gave a short lecture on case-based reasoning, we talked about commas. Fun was had by all, I think.

On a more general note, I closed our conversation with a suggestion that perhaps they could draw on lessons they learn writing, documenting, and explaining programs to help them write prose. Take small steps when writing new content, not worrying as much about form as about the idea. Then refactor: spend time reworking the prose, rewriting, condensing, and clarifying. In this phase, we can focus on how well our text communicates the ideas it contains. And, yes, good structure can help, whether at the level of sentences, paragraphs, or then whole essay.

I enjoyed the coincidence of later reading this passage in Roy Behrens's blog, The Poetry of Sight:

Fine advice from poet Richard Hugo in The Triggering Town: Lectures and Essays on Poetry and Writing (New York: W.W. Norton, 1979)--

Lucky accidents seldom happen to writers who don't work. You will find that you may rewrite and rewrite a poem and it never seems quite right. Then a much better poem may come rather fast and you wonder why you bothered with all that work on the earlier poem. Actually, the hard work you do on one poem is put in on all poems. The hard work on the first poem is responsible for the sudden ease of the second. If you just sit around waiting for the easy ones, nothing will come. Get to work.

This is an important lesson for programmers, especially relative beginners, to learn. The hard work you do on one program is put in on all programs. Get to work. Write code. Refactor. Writing teaches writing.

~~~~

Long-time readers of this blog may recall that I once recommended The Triggering Town in an entry called Reading to Write. It is still one of my favorites -- and due for another reading soon!


Posted by Eugene Wallingford | Permalink | Categories: General, Software Development

April 10, 2011 9:23 PM

John McPhee on Writing, Teaching, and Programming

John McPhee is one of my favorite non-fiction writers. He is a long-form journalist who combines equal measures of detailed fact gathering and a literary style that I enjoy as a reader and aspire to as a writer. For years, I have used selections from the The John McPhee Reader in advice to students on how to do gather requirements for software, including knowledge acquisition for AI systems.

This weekend I enjoyed Peter Hessler's interview of McPhee in The Paris Review, John McPhee, The Art of Nonfiction No. 3. I have been thinking about several bits of McPhee's wisdom in the context of both writing and programming, which is itself a form of writing. I also connected with a couple of his remarks about teaching young writers -- and programmers.

One theme that runs through the interview serves as a universal truth connecting writing and programming:

Writing teaches writing.

In order to write or to program, one must first learn the basics, low-level skills such as grammar, syntax, and vocabulary. Both writers and programmers typically go on to learn higher-level skills that deal with the structure of larger works and the patterns that help creators create and readers understand. In the programming world, we call these "design" skills, though I imagine that's too much an engineering term to appeal to writes.

Once you have these skills under your belt, there isn't much more to teach, but there is plenty to learn. We help newbies learn by sharing what we create, by reading and critiquing each others work, and by talking about our craft. But doing it -- writing, whether it's stories, non-fiction, or computer programs -- that's the thing.

McPhee learned this in many ways, not the least of which was one of the responses he received to his first novel, which he wrote in lieu of a dissertation (much to the consternation of many Princeton English professors!). McPhee said

It had a really good structure and was technically fine. But it had no life in it at all. One person wrote a note on it that said, You demonstrated you know how to saddle a horse. Now go find the horse.

He still had a lot to learn. This is a challenge for many young programmers whom I teach. As they learn the skills they need to become competent programmers, even excellent ones, they begin to realize they also need a purpose. At a miniconference on campus last week, a successful former student encouraged today's students to find and nurture their own passions. In those passions they will also find the energy and desire to write, write, write, which is the only he knew of to master the craft of programming.

Finding passion is hard, especially for students who come through an educational system that sometimes seems more focused on checking off boxes than on growing a person.

Luckily, though, finding problems to work on (or stories to write) can be much less difficult. It requires only that we are observant, that we open our eyes and pay attention. As McPhee says:

There are zillions of ideas out there--they stream by like neutrons.

For McPhee, most of the ideas he was willing to write about, spending as much as three years researching and writing, relate to things he did when I was a kid. That's not too far from the advice we give young software developers: write the programs you need or want to use. It's okay to start with what you like and know even if no one else wants those things. First of all, maybe they do. And second, even if they really don't, those are the problems on which you will be willing to work. Programming teaches programming.

Keep in mind: finding ideas isn't enough. You have to do the work. In the end, that is the measure of a writer as well as the measure of a programmer.

If you have already found your passion, then finding cool things to do gets even easier. Passion and obsession seem to heighten our senses, making it easier to spot potential new ideas and solution. I just saw a great example of this in the movie The Social Network, when an exhausted Mark Zuckerberg found the insight for adding Relationship Status to Facebook from a friend's plaintive request for help finding out whether a girl in his Art History class was available.

So, you have an idea. How long does it take to write?

... It takes as long as it takes. A great line, and it's so true of writing. It takes as long as it takes.

Despite what we learn in skill, this is true of most things. They take however long they take. This was a hard lesson for me to learn. I was a pretty good student in school, and I learned early on how to prosper in the rhythm of the quarter, semester, and school year. Doing research in grad school helped me to see that real problems are much messier, much less predictable than the previous sixteen years of school had led me to believe.

As a CS major, though, I began to learn this lesson in my last year as an undergrad, writing the program at the core of my senior project. It takes as long as it takes, whatever the university's semester calendar says. Get to work.

As a teacher, I found most touching an answer McPhee gave when asked why he still teaches writing courses at Princeton. He is well past the usual retirement age and might be expected to slow down, or at least spend all of his time on his own writing. Every teacher who reads the answer will feel its truth:

But above all, interacting with my students--it's a tonic thing. Now I'm in my seventies and these kids really keep me alive. To talk to a nineteen-year-old who's really a good writer, and he's sitting in here interested in talking to me about the subject--that's a marvelous thing, and that's why I don't want to stop.

As I read this, my mind began to recount so many students who have changed me as a programmer and teacher. The programmer, artist, and musician who wanted to write a program that could express artistic style, who is now a filmmaker inflamed with understanding man and his relationship to the world. The high school kid with big ideas about fonts, AI, and design whose undergrad research qualified for a national ACM competition and who is now a research scientist at Apple. The brash PR student who wanted to become a programmer and did, writing a computer science thesis and an even more important communications studies thesis, who is now set on changing how we study and understand human communication in the age of the web. The precocious CS student whose ideas were bigger than my courses before he set foot in my classroom, who worked hard learning things beyond what we were teaching and eventually doubling back to learn what he had missed, an entrepreneur with a successful tech start-up who is now helping a new generation of students learn and dream.

The list could go on. Teaching keeps us alive. Students learn, we hope, and so do we. They keep us in the present, where the excitement of new ideas is fresh. And, as McPhee admits with no sense of shame or embarrassment, it is flattering, too.


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

March 29, 2011 8:13 PM

Global Variables Considered

Last week, a student stopped in to ask a question. He had written a program for one of his courses of which he was especially proud. It consisted in large part of two local functions, and used recursion in a way that created an elegant, clear solution.

Yet his professor dinged his grade severely. The student had used a global variable.

That's when the question for me arrived.

But why are we taught not to use global variables?

First, let me say that this a strong student. He is not the sort to beg for points, and he wasn't asking me this question as a snark or a complaint. He really wanted to know the answer.

My first response was cynical and at least partly tongue-in-cheek. We teach you not to use global variables because we were taught to use global variables.

My second response was to point out that "global" is a relative term, not an absolute one. In OO languages, we write classes that contain instance variables and methods that operate on them. The instance variables are global to class's methods and local to class's clients. The programming world seems to like such "globals" just fine.

That is the beginning of my trouble trying to create an argument that supports the way in which his program was graded. In his program, written in a traditional procedural language, the offending variable was local to one procedure but global to two nested procedures. That sounds awfully similar to an ordinary Java class's instance variables!

On the extreme end of the global/local continuum we have a language like Cobol. All data is declared at the top of a program in an elaborate Data Division, and the "paragraphs" of the Procedure Division refer back to it. Not many computer scientists spend much time defending Cobol, but its design and organization make perfectly good sense in context, and programmers are able to write understandable, large programs.

As the student and I talked, I explained two primary reasons for the historical bias against globals:

Readability. When a variable lives outside the code that manipulates it, there is a chance that it can become separated in space from that code. As a large program evolves over time, it seems that the chance the variable will become separated from the related code approaches 1. That makes the code hard to understand. When the reader encounters a variable, she may have a hard time knowing what it means without seeing the code that uses it. When she encounters a procedure with a reference to a faraway variable, she may have a hard time knowing what the code does without easy reference to the variable and any other code that uses it.

This force is counteracted effectively in some circumstances. In OOP, we try not to write classes that are too long, which means that the instance vars and the methods will be relatively close to one another in the file or on the printed page. Furthermore, there is a convention that the vars will be declared at the top or bottom of the class, so the reader can always find them easily enough. That's part of what makes Cobol's layout work: readers study the Data Division first and then read the Procedure Division with an eye to the top of the file.

My student's programming had a structure that mirrored a small class: a procedure with a variable and two local procedures of reasonable size. I can imagine endorsing the relatively global variable because it was part of a understandable, elegant program.

Not-Obvious Dependencies. When two or more procedures operate on the same variable that lives outside all of them, there is a risk of that lack of readability rises to something worse: an inability to divine how the program works. The two procedures exert influence over each other's behavior through the values stored in the shared variable. In OO programs, this interaction is an expected part of how objects behave, and we try to keep methods and the class as a whole small enough to counteract the problem.

In the general case, though, we can end up with variables and procedures scattered throughout a program and interacting in non-obvious ways. A change to one procedure might affect another. Adding another procedure that refers to or changes the variable complicates matters for all existing procedures in the co-dependent relationship. Hidden dependencies are the worst kind of all.

This is what really makes global variables bad for us. Unless we can counteract this force effectively, we really don't want to use them.

These are two simple technical reasons that programmers prefer not to use global variables. CS professors tend to simplify them into the dictum, "no global variables allowed", and make it a hard and fast rule for beginners. Unfortunately, sometimes we forget to take the blinders off after our students -- or we ourselves! -- become more accomplished programmers. The dictum becomes dogma, and a substitute for professional judgment.

I have what I regard as a healthy attitude about global variables. But I admitted to my student that I have my own weakness in the dictum-turned-dogma arena. When I teach OOP to beginners, we follow the rule All instance variables are private. I'm a reasonable guy and so am willing to talk to students who want to violate the rule, but it's pretty much non-negotiable. I've never had a first- or second- year OOP student convince me that one of his IVs should protected or -- heaven forbid! -- public. But even in my own code, after a couple of decades of doing OOP, I rarely violate this rule. I say "rarely" only in the interest of being conservative in my assessment. I can't remember the last time I wrote a class with a public instance variable.

Not all teachers are good at giving up their dogma. Some professors don't even realize that what they believe is best thought of as an oversimplification for the purposes of helping novices develop good habits of thought.

Ironically, last semester I ran across the paper Global Variable Considered Harmful, by Bill Wulf and Mary Shaw. (If you can't get through the ACM paywall, you can also find the paper here.) This is, I think, the first published attempt to explain why the global variable is a bad idea. Read it -- it's a nice treatment of the issues as they existed back in 1973. Forty years later, I am comfortable using variables that are relatively global to one or more procedures under controlled conditions. At this point in my programming career, I willing to use my professional judgment to help me make good programs, not just programs that follow the rules.

I shared the Wulf and Shaw paper with my student. I hope he got a kick out of it, and I hope he used it to inform his already reliable professional judgment. The paper might even launch him ahead of the profs who teach the prohibition on global variables as if it were revealed truth.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

March 25, 2011 4:40 PM

Another Conference Changes Its Name

Ralph Johnson reports that "the conference on aspect oriented software development is renaming itself to 'Modularity'", much as OOPSLA has become SPLASH.

For the last couple of decades, computer science research has been focusing on more and more specific domains. The area of artificial intelligence, for example, soon spawned journals and conferences devoted specifically to sub-areas such as machine learning, expert systems, computer vision, and many others. It's interesting for me to see conferences such as AOSD and OOPSLA going the other direction, moving from the technology that spawned the conference in the first place to the more general idea or goal that motivates its community.

Of course, these conferences aren't purely academic; they have always had a strong alliance between industry and academia. Perhaps that is one of the reasons they are willing to rebrand themselves. Certainly, the changing economic model that drives this sort of conference is playing a big role.

By the way, Ralph's entry isn't really about the changing conference name. He merely uses that as a launching point for something more interesting: a first cut at cataloging different types of modularity. That is the best reason to read it!


Posted by Eugene Wallingford | Permalink | Categories: Software Development

March 23, 2011 8:13 PM

SPLASH 2011 and the Educators' Symposium

I have been meaning to write about SPLASH 2011 and especially the Educators' Symposium for months, and now I find that Mark Guzdial has beaten me to the punch -- with my own words, no less! Thanks to Mark for spreading the news. Go ahead and read his post if you'd like to see the message I sent to the SIGCSE membership calling for their submissions. Or visit the call for participation straightaway and see what the program committee has in mind. Proposals are due on April 8, only a few weeks hence. Dream big -- we are.

For now, though, I will write the entry I've been intending all these months:

The Next Ten Years of Software Education

SPLASH 2011 in Portland, Oregon

By the early 2000s, I had become an annual attendee of OOPSLA and had served on a few Educators' Symposium program committees. Out of the blue, John Vlissides asked me to chair the 2004 symposium. I was honored and excited. I eventually got all crazy and cold called Alan Kay and asked him to deliver our keynote address. He inspired us with a vision and ambitious charge, which we haven't been able to live up to yet.

When I was asked to chair again in 2005, we asked Ward Cunningham to deliver our keynote address. He inspired us with his suggestions for nurturing simple ideas and practices. It was a very good talk. The symposium as whole, though, was less successful at shaking things than in 2004. That was likely my fault.

I have been less involved in the Educators' Symposium since 2006 or 2007, and even less involved in OOPSLA more broadly. Being department head keeps me busy. I have missed the conference.

Fast-forward to 2010. OOPSLA has become SPLASH, or perhaps more accurately been moved under the umbrella of SPLASH. This is something that we had talked about for years. 2011 conference chair Crista Lopes was looking for a Educators' Symposium chair and asked me for any names I might suggest. I admitted to her that I would love to get involved again, and she asked me to chair. I'm back!

OOPSLA was OO, or at least that what its name said. It had always been about more, but the name brand was of little value in a corporate world in which OOP is mainstream and perhaps even passe. Teaching OOP in the university and in industry has changed a lot over the last ten years, too. Some think it's a solved problem. I think that's not true at all, but certainly many people have stopped thinking very hard about it.

In any case, conference organizers have taken the plunge. SPLASH != OOPSLA and is now explicitly not just about OO. The new conference acknowledges itself to be about programming more generally. That makes the Educators' Symposium something new, too, something more general. This creates new opportunities for the program committee, and new challenges.

We have decided to build the symposium around a theme of "The Next Ten Years". What ideas, problems, and technologies should university educators and industry trainers be thinking about? The list of possibilities is long and daunting: big data, concurrency, functional programming, software at Internet scale... and even our original focus, object-oriented programming. Our goal for the end of the symposium is to be able to write a report outlining a vision for software development education over the next ten years. I don't expect that we will have many answers, if any, but I do expect that we can at least begin to ask the right questions.

And now here's your chance to help us chart a course into the future, whether you plan to submit a paper or proposal to the symposium:

Who would be a killer keynote speaker?

What person could inspire us with a vision for computer science and software, or could ask us the questions we need to be asking ourselves?

Finding the right keynote speaker is one of the big questions I'm thinking about these days. Do you have any ideas? Let me know.

(And yes, I realize that Alan Kay may well still be one of the right answers!)

In closing, let me say that whenever I say "we" above, I am not speaking royally. I mean the symposium committee that has graciously offered their time and energy to designing implementing this challenge: Curt Clifton, Danny Dig, Joe Bergin, Owen Astrachan, and Rick Mercer. There are also a handful of people who have been helping informally. I welcome you to join us.


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

March 04, 2011 5:25 PM

The Growing Buzz around Empirical Analysis of Repositories

This has turned into a recurring theme, due to a hopeful trend out in industry.

Last semester, I wrote a bit about studying program repositories as a way to understand how programmers work. Then last month, I wrote about simple empirical analysis of code, referring to Michael Feathers's article on how we can learn a lot about our program's design by looking at our commit log. Feathers went on to write a short note about getting empirical about refactoring, in which he expanded on the idea of looking at our code to understand its design better.

Now we have Turbulence, a package for pulling useful metrics about our code out of a git repository. The package began its life when Feathers and Corey Haines wrote a script to plot code churn versus its complexity. Haines has written a bit about the Turbulence project.

It doesn't end there. Developers are using Turbulence and adding to its code base. Feathers's has called for a renewed focus on design in the wild using the data we have at our fingertips. The physicians have begun to heal themselves, and they are leading the way for the rest of us.

One nice side effect of this trend is making available to a wider audience some of the academic research that has been done in this vein, such as Nagappan and Ball's paper on code churn and defect density. (I had the pleasure of meeting Ball when we served on a panel at OOPSLA several years ago.)

As many people are saying, we swim in data. We just have to find ways to use it well. I remain ever amazed at what our tools enable us to do.

All this talk about git has me resolved to go all the way and make a full switch to it. I've dabbled with git a bit and consumed a lot of software off GitHub, but now it's time to do all my development in it. Fortunately, there are a few excellent resources to help me, including the often-lauded Git Immersion guided tour by Jim Weirich and crew. and Scott Chacon's visually engaging Getting Git slidedeck. My trip to to SIGCSE and the spring break that follows immediately after can't come to soon!


Posted by Eugene Wallingford | Permalink | Categories: Software Development

February 22, 2011 4:06 PM

Nothing From Scratch

Over the weekend, I enjoyed re-reading Brian Foote's The Craftsmen vs. the Scavengers, which is subtitled "The Ruminations of a Foot Soldier on the Reuse Revolution". Foote expressed an idea that has been visited and re-visited every so often in recent years:

In a world dominated by code reuse, all programming, will, in one sense, be maintenance programming.

Foote was a student of Ralph Johnson, who has written and spoken occasionally about the idea that software development is program transformation. I blogged about Ralph's idea and what it meant for me nearly five years ago, just before teaching an intro CS course that emphasized the modification and extension of existing code.

Some people worry that if we don't start students off with writing their own code from scratch they won't really learn to program. Most of the students in that CS1 course have turned out to be pretty good programmers; that's just anecdote, of course, and not evidence that the approach is write or wrong. But at least I don't seem to have done them irreparable harm.

This idea is comfortable to me as an old Smalltalk programmer. As Foote elaborates, the Smalltalk toolset supports this style of programming and, more importantly, the Smalltalk culture encouraged code reuse, sharing, and a sense of collective code ownership. We all felt we were in the same boat -- the same image -- together.

The commingling of Foote's assertion and my recollection of that CS1 course caused my mind to wander down another path. What about those times when we do start with a blank slate on a new project? If we approach the task as programming from scratch, we might well design a complete solution and try to implement it as a single piece. When I do maintenance programming, I don't usually think that way, even when I have a major change to make to the program. I'm usually too scared to change too many things at once! Instead, I make a series of small changes to the code, coaxing and pruning the system toward the goal state. This is, I think, just what XP and TDD encourage us to do even when we code on a blank slate. It's an effective way to think about writing new programs.

The very next section of Foote's paper also caused echoes in my mind. It suggest that, in a culture of reuse, bad design might drive out good design simply by being there first and attracting an audience. Good design takes a while to evolve, and by the time it matures a mediocre library or framework might already control the niche. This may have happened in some parts of the Smalltalk world, but I was lucky not to encounter it very often. Foote's idea comes across as another form Gresham's Law for software design, so long as we are willing to mangle the original sense of that term. The effect is similar: the world ends up trafficking in a substandard currency.

It sobers me to note that Foote wrote this paper in the summer of 1989. These ideas aren't new and have been on the software world's mind since at least the shift to OOP began twenty-five years ago or so. There truly is nothing new for me to say. As a community, though, we revisit these ideas from different vantage points as we evolve. Perhaps we can come away with new understanding as a result.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

February 10, 2011 4:04 PM

This and That: Problems, Data, and Programs

Several articles caught my eye this week which are worth commenting on, but at this point none has triggered a full entry of its own. Some of my favorite bloggers do what they call "tab sweeps", but I don't store cool articles in browser tabs. I cache URLs and short notes to myself. So I'll sweep up three of my notes as a single entry, related to programming.

Programmer as Craftsman

Seth Godin writes about:

... the craftsperson, someone who takes real care and produces work for the ages. Everyone else might be a hack, or a factory guy or a suit or a drone, but a craftsperson was someone we could respect.

There's a lot of talk in the software development world these days about craftsmanship. All the conversation and all the hand-waving boil down to this. A craftsman is the programmer we all respect and the programmer we all want to be.

Real Problems...

Dan Meyer is an erstwhile K-12 math teacher who rails against the phony problems we give kids when we ask them to learn math. Textbooks do so in the name of "context". Meyer calls it "pseudocontext". He gives an example in his entry Connect These Two Dots, and then explains concisely what is wrong with pseudocontext:

Pseudocontext sends two signals to our students, both false:
  • Math is only interesting in its applications to the world, and
  • By the way, we don't have any of those.

Are we really surprised that students aren't motivated to practice and develop their craft on such nonsense? Then we do the same things to CS students in our programming courses...

... Are Everywhere These Days

Finally, Greg Wilson summarizes what he thinks "computational science" means in one of his Software Carpentry lessons. It mostly comes down to data and how we understand it:

It's all just data.

Data doesn't mean anything on its own -- it has to be interpreted.

Programming is about creating and composing abstractions.

...

The tool shapes the hand.

We drown in data now. We collect faster than we can understand it. There is room for more programmers, better programmers, across the disciplines and in CS.

We certainly shouldn't be making our students write Fahrenheit-to-Celsius converters or processing phony data files.


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

February 07, 2011 9:03 PM

Teaching and Learning in a Code Base

In a pair of tweets today, Brian Marick offered an interesting idea for designing instruction for programmers:

A useful educational service: examine a person's codebase. Devise a new feature request that would be hard, given existing code and skill...

... Keep repeating as the codebase and skill improve. Would accelerate a programmer's skill at dealing with normal unexpected change.

This could also be a great way to help each programmer develop competencies that are missing from his or her skill set. I like how this technique would create an individualized learning for each student. The cost, of course, is in the work needed by the instructor to study the codebases and devise the feature requests. With a common set of problems to work on, over time an instructor might be able to develop a checklist of (codebase characteristic, feature request) pairs that covered a lot of the instructional space. This idea definitely deserves some more thought!

Of course, we can sometimes analyze valuable features of a codebase with relatively simple programs. Last month, Michael Feathers blogged about measuring the closure of code, in which he showed how we can examine the Open/Closed Principle in a codebase by extracting and plotting the per-file commit frequencies of source files in a project's version control repository. Feathers discussed how developers could use this information intentionally to improve the quality of their code. I think this sort of analysis could be used to great effect in the classroom. Students could see the OCP graphically for a number of projects and, combined with their programming knowledge of the projects, begin to appreciate what the OCP means to a programmer.

A serendipitous side effect would be for students to experience CS as an empirical discipline. This would help us prepare developers more readily in sync with Feathers's use of analytical data in their practice and CS grads who understand the ways in which CS can and should be an empirical endeavor.

I actually blogged a bit about studying program repositories last semester, for the purpose of understanding how to design better programming languages. That work used program repositories for research purposes. What I like about Marick's and Feathers's recent ideas is that they bring to mind how studying a program repository can aid instruction, too. This didn't occur to me so much back when one of my grad students studied relationships among open-source software packages with automated analysis of a large codebase. I'm glad to have received a push in that direction now.


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

February 03, 2011 3:30 PM

Science and Engineering in CS

A long discussion on the SIGCSE members listserv about math requirements for CS degrees has drifted, as most curricular discussions seem to do, to "What is computer science?" Somewhere along the way, someone said, "Computer Science *is* a science, by name, and should therefore be one by definition". Brian Harvey responded:

The first thing I tell my intro CS students is "Computer Science isn't a science, and it isn't about computers." (It should be called "information engineering.")

I think that this assertion is wrong, at least without a couple of "only"s thrown in, but it is a great way to start a conversation with students.

I've been seeing the dichotomy between CS as science and CS as system-building again this semester in my Intelligent course. The textbook my students used in their AI course last semester is, like nearly every undergrad AI text, primarily an introduction to the science of AI: a taxonomy of concepts, results of research that help to define and delimit the important ideas. It contains essentially no pragmatic results for building intelligent systems. Sure, students learn about state-space search, logic as a knowledge representation, planning, and learning, along with algorithms for the basic methods of the field. But they are not prepared for the fact that, when they try to implement search or logical inference for a given problem, they still have a huge amount of work to do, with little guidance from the text.

In class today, we discussed this gap in two contexts: the gap one sees between low-level programming and high-level programming languages, and the difference between general-purpose languages and domain-specific languages.

My students seemed to understand my point of view, but I am not sure they really grok it. That happens best after they gain experience writing code and feel the gap while making real systems run. This is one of the reasons I'm such a believer in projects, real problems, and writing code. We don't always understand ideas until we see them in a concrete.

I don't imagine that intro CS students have any of the experience they need to understand the subtleties academics debate about what computer science is or what computer scientists. We are almost surely better off asking them to do something that matters them, whether a small problem or a larger project. In these problems and projects, students can learn from us and from their own work what CS is and how computer scientists think.

Eventually, I hope that the students writing large-ish AI programs in my course this semester learn just how much more there is to writing an intelligent system than just implementing a general-purpose algorithm from their text. The teams that are using pre-existing packages as part of they system might even learn that integrating software systems is "more like performing a heart transplant than snapping together LEGO blocks". (Thanks to John Cook for that analogy.)


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

January 27, 2011 4:48 PM

Turning Up the Knob on Functional OOP and Imperative OOP

One of my students has been learning Haskell as a prelude to exploring purely functional data structures. Recently, he wrote a short blog entry describing some of the ideas he has found most exciting. It ended with a couple of code snippets showing the elegance and brevity of list comprehensions compared to what he was used to in imperative languages. The student apologized for his imperative example, because he wrote it in Java using objects. In his mind, that made it object-oriented, not imperative.

This is a common misconception. Most OOP is imperative. Objects have state that changes.

Of course, one can write object-oriented code in a functional style by emphasizing return values and by creating new objects instead of changing existing objects. Certain kinds of objects, such as money, should probably be implemented as value objects without modifiable state. But most OO practice and intent is stateful, hence imperative.

I've read many a blog entry over the last few years in which OO gurus extol functional OO as a way to write better code. I think we can overdo it, though. Whenever I take this idea too far, though, I soon find myself contorting the code in a way that seems to serve the idea but not the program I am writing. Still, sometimes it can be fun to turn the knob on the functional OO dial up to 10 and try to write purely functional OO code, with no side effects of any sort. This kind of programming challenge has always appealed to me. It can teach you a lot about the strengths and limits of the tools you use.

It occurs to me that one way to enforce the rules of the functional OO challenge would be to turn off the imperative features in my language. That can be tough to do in a language with libraries full of stateful objects. But simply turning off the assignment operator in a language such as Java would make many of us struggle to write even simple programs.

Actually, I had the idea of turning off assignment statements late in a long conversation I had with myself while thinking about my student's comment and my response to him. If most OO is imperative, I wonder what it would be like to write "purely imperative" OO code. This would mean creating objects that never returned a value in response to a message. In a sense, these objects would be pure state and action, at least from the perspective of other objects in the system.

At first, this idea seemed absurd. What value could come from it?

This stylistic challenge is quite easy to enforce, either in practice or in tools: simply require all methods to be void. Voilé! No return statements are allowed. No values can be passed from one object to another in response to a message. An object would affect the state of the program either by modifying its own state or by sending a state-changing message to another object, perhaps an argument that it received along with a message.

Talk about Tell, Don't Ask! In this style of programming, I can only tell objects to do things. I can't ask for any data in return.

So, perhaps some value could come from this little challenge after all. I would have to take Tell, Don't Ask -- and encapsulation -- seriously. Programming in this way can help us see just how much we can accomplish with truly independent objects, providers of services who encapsulate their state and take full responsibility for its management. I think that, in many respects, this idea is faithful to the original idea of objects and OOP -- perhaps more faithful than our current incarnation of them in languages with functions.

I think that this could also help us in another way. Functional programming offers us one path to increased parallelism by eliminating state changes and thus making each computation independent of global context. Purely imperative programming offers another path, one that fits the early OO vision of encapsulated agents interacting via message passing. This is similar to the actor model that we see these days in languages such as Scala and Erlang. Of course, this model goes back to the work of Carl Hewitt, which inspired the evolution of both Scheme and Smalltalk!

I have not thought through all the implications of my thought experiment yet. Maybe it's nonsense; maybe it's a solved problem. Still, I think it might be fun to turn the dial up to 10 on stateful programming and try to implement a non-trivial program with no return statements. How far could I go before things got uncomfortable? How far could I go before I found myself contorting the code in a way that serves the idea more than the program I was writing?

Sometimes I am surprised just how many interesting thoughts can fall out of the simplest conversations. Too bad time to play with them doesn't fall out, too.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

December 20, 2010 3:32 PM

From Occasionally Great to Consistently Good

Steve Martin's memoir, "Born Standing Up", tells the story of how Martin's career as a stand-up comedian, from working shops at Disneyland to being the biggest-selling concert comic ever at his peak. I like hearing people who have achieved some level of success talk about the process.

This was my favorite passage in the book:

The consistent work enhanced my act. I Learned a lesson: It was easy to be great. Every entertainer has a night when everything is clicking. These nights are accidental and statistical: Like the lucky cards in poker, you can count on them occurring over time. What was hard was to be good, consistently good, night after night, no matter what the abominable circumstances.

"Accidental greatness" -- I love that phrase. We all like to talk about excellence and greatness, but Martin found that occasional greatness was inevitable -- a statistical certainty, even. If you play long enough, you are bound to win every now and then. Those wines are not achievement of performance so much as achievements of being there. It's like players and coaches in athletics who break records for the most X in their sport. "That just means I've been around a long time," they say.

The way to stick around a long time, as Martin was able to do, is to be consistently good. That's how Martin was able to be present when lightning struck and he became the hottest comic in the world for a few years. It's how guys like Don Sutton won 300+ games in the major leagues: by being good enough for a long time.

Notice the key ingredients that Martin discovered to becoming consistently good: consistent work; practice, practice, practice, and more practice; continuous feedback from audiences into his material and his act.

We can't control the lightning strikes of unexpected, extended celebrity or even those nights when everything clicks and we achieve a fleeting moment of greatness. As good as those feel, they won't sustain us. Consistent work, reflective practice, and small, continuous improvements are things we can control. They are all things that any of us can do, whether we are comics, programmers, runners, or teachers.


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

December 11, 2010 11:55 AM

Don't Forget to Solve Your Problem a Second Time

The Toyota Production System encourages workers to solve every problem two ways. First, you fix the issue at hand. Second, you work back through the system to determine the systemic reason that the issue arose. In this way, you eliminate this as a problem in the future, or at least make it less likely.

As I wrote recently, I don't think of writing software as a production process. But I do think that software developers can benefit from the "solve it twice" mentality. When we encounter a bug in our program or a design problem in our system or a delivery problem on a project, we should address the specific issue at hand. Then we should consider how we might prevent this sort of problem from recurring. There are several ways that we might improve:

  • We may need better or different tools.
  • We may be able to streamline or augment our process.
  • We may need to think about different things while working.
  • We may need to know something more deeply, or something new.

This approach would benefit us as university students and university professors, too. If students and professors thought more often in terms of continuous improvement and committed to fixing problems the second time, too, we might all have lower mean times to competence.


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

December 03, 2010 3:56 PM

A Commonplace for Novelists and Programmers

To be a moral human being is to pay, be obliged to pay, certain kinds of attention.

-- Susan Sontag, "The Novelist and Moral Reasoning"

For some reason, this struck me yesterday as important, not just as a human being, but also as a programmer. I am reminded that many of my friends and colleagues in the software world speak passionately of our moral obligations when writing code. The software patterns community, especially, harkens to Christopher Alexander's call regarding the moral responsibility of creators.

(If you want to read more from Sontag without tracking down her essay, check out this transcript excerpted from a speech she gave in 2004.)


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

December 01, 2010 3:45 PM

"I Just Need a Programmer"

As head of the Department of Computer Science at my university, I often receive e-mail and phone calls from people with The Next Great Idea. The phone calls can be quite entertaining! The caller is an eager entrepreneur, drunk on their idea to revolutionize the web, to replace Google, to top Facebook, or to change the face of business as we know it. Sometimes the caller is a person out in the community; other times the caller is a university student in our entrepreneurship program, often a business major. The young callers project an enthusiasm that is almost infectious. They want to change the world, and they want me to help them!

They just need a programmer.

Someone has to take their idea and turn it into PHP, SQL, HTML, CSS, Java, and Javascript. The entrepreneur knows just what he or she needs. Would I please find a CS major or two to join the project and do that?

Most of these projects never find CS students to work on them. There are lots of reasons. Students are busy with classes and life. Most CS students have jobs they like. Those jobs pay hard cash, if not a lot of it, which is more attractive to most students than the promise of uncertain wealth in the future. The idea does not excite other people as much as the entrepreneur, who created the idea and is on fire with its possibilities.

A few of the idea people who don't make connections with a CS student or other programmer contact me a second and third time, hoping to hear good news. The younger entrepreneurs can become disheartened. They seem to expect everyone to be as excited by their ideas as they are. (The optimism of youth!) I always hope they find someone to help them turn their ideas into reality. Doing that is exciting. It also can teach them a lot.

Of course, it never occurs to them that they themselves could learn how to program.

A while back, I tweeted something about receiving these calls. Andrei Savu responded with a pithy summary of the phenomenon I was seeing:

@wallingf it's sad that they see software developers as commodities. product = execution != original idea

As I wrote about at greater length in a recent entry, the value of a product comes from the combination of having an idea and executing the idea. Doing the former or having the ability to do the latter aren't worth much by themselves. You have to put the two together.

Many "idea people" tend to think most or all of the value inheres to having the idea. Programmers are a commodity, pulled off the shelf to clean up the details. It's just a small matter of programming, right?

On the other side, some programmers tend to think that most or all of the value inheres to executing the idea. But you can't execute what you don't have. That's what makes it possible for me and my buddy to sit around over General Tsao's chicken and commiserate about lost wealth. It's not really lost; we were never in its neighborhood. We were missing a vital ingredient. And there is no time machine or other mechanism for turning back the clock.

I still wish that some of the idea people had learned how to program, or were willing to learn, so that they could implement their ideas. Then they, too, could know the superhuman strength of watching ideas become tangible. Learning to program used to be an inevitable consequence of using computers. Sadly, that's no longer true. The inevitable consequence of using computers these days seems to be interacting with people we may or may not know well and watching videos.

Oh, and imagining that you have discovered The Next Great Thing, which will topple Google or Facebook. Occasionally, I have an urge to tell the entrepreneurs who call me that their ideas almost certainly won't change the world. But I don't, for at least two reasons. First, they didn't call to ask my opinion. Second, every once in a while a Microsoft or Google or Facebook comes along and does change the world. How am I to know which idea is that one in a gazillion that will? If my buddy and I could go back to 2000 and tell our younger and better-looking selves about Facebook, would those guys be foresightful enough to sit down and write it? I suspect not.

How can we know which idea is that one that will change the world? Write the program, work hard to turn it into what people need and want, and cross our fingers. Writing the program is the ingredient the idea people are missing. They are doing the right thing to seek it out. I wonder what it would be like if more people could implement their own ideas.


Posted by Eugene Wallingford | Permalink | Categories: General, Software Development

November 29, 2010 2:34 PM

Cleaning Up Versus Not Getting Dirty

In his 2008 letter to Amazon shareholders, Jeff Bezos wrote this oft-quoted footnote:

At a fulfillment center recently, one of our Kaizen experts asked me, "I'm in favor of a clean fulfillment center, but why are you cleaning? Why don't you eliminate the source of dirt?" I felt like the Karate Kid.

When I first read this in a blog entry, I immediately thought of refactoring. I favor a style of programming in which "cleaning up" is a fundamental step: pick a small bit of new functionality, do the simplest thing I can to make it work, and then clean up the program's design and implementation. Should I instead eliminate the source of dirt, and think far enough ahead that the program is always clean?

It didn't take me long to realize that I'm neither smart enough nor well enough informed about most problems to do that. I will have to clean up every so often, no matter how far I think ahead. Besides, I find so much value in taking small steps and doing simple things that I am willing to clean up.

Why is that? Why am I willing to clean up, rather than keep things clean from the start? Why does refactoring work for software developers?

If things are too clean, you probably are not creating new things.

Kaizen notions are attractive to many in the "lean" world of software development, and it is important -- in context. Production and creation are different kinds of task. Keeping things clean and efficient has great value in production environments, including factories and perhaps in certain kinds of software development. But when you are making new things, there is great value in exploration, and exploration is messy.

Bezos wrote that footnote on this passage:

Everywhere we look (and we all look), we find what experienced Japanese manufacturers would call "muda" or waste. I find this incredibly energizing. I see it as potential -- years and years of variable and fixed productivity gains and more efficient, higher velocity, more flexible capital expenditures.

Amazon is a company that makes most of its profit by delivering product to customers more efficiently and less expensively than its competitors. If it can eliminate a source of muda, it becomes a better company. That's why the Kaizen expert's advice gave Bezos a Karate Kid moment.

For me, the Karate Kid moment was just the opposite: when I learned that programmers had vocabulary for talking about refactoring and that some experts had made it a deliberate part of their development process. Wax on, wax off.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

November 19, 2010 4:45 PM

Debugging the Law

Debugging the Law

Recently, Kevin Carey's Decoding the Value of Computer Science got a lot of play among CS faculty I know. Carey talks about how taking a couple of computer programming courses way back at the beginning of his academic career has served him well all these years, though he ended up majoring in the humanities and working in the public affairs sector. Some of my colleagues suggested that this article gives great testimony about the value of computational thinking. But note that Carey didn't study abstractions about computation or theory or design or abstraction. He studied BASIC and Pascal. He learned computer programming.

Indeed, programming plays a central role in the key story within the story. In his first job out of grad school, Carey encountered a convoluted school financing law in my home state of Indiana. He wrote code to simulate the law in SAS and, between improving his program and studying the law, he came to understand the convolution so well that he felt confident writing a simpler formula "from first principles". His formula became the basis of an improved state law.

That's right. His code was so complicated and hard to maintain, he through the system away and wrote a new one. Every programmer has lived this experience with computer code. Carey tried to debug a legal code and found its architecture to be so bad that he was better off creating a new one.

CS professors should use this story every time they try to sell the idea of universal computer programming experience to the rest of the university!

The idea of refactoring legal code via a program that implements it is not really new. When I studied logic programming and Prolog in grad school, I read about the idea of expressing law as a Prolog programming and using the program to explore its implications. Later, I read examples where Prolog was used to do just that. The AI and law community still works on problems of this sort. I should dig into some of the recent work to see what progress, if any, has been made since I moved away from that kind of work.

My doctoral work involved modeling and reasoning about legal arguments, which are very much like computer programs. I managed to think in terms of argumentation patterns, based on the work of Stephen Toulmin (whose work I have mentioned here before). I wish I had been smart or insightful enough to make the deeper connection from argumentation to software development ideas such as architecture and refactoring. It seems like there is room for some interesting cross-fertilization.

(As always, if you know about work in this domain, please let me know!)


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

November 16, 2010 3:59 PM

Agile Moments: The Value of Smaller

Yesterday I read two articles that highlight, in different ways, the value of smaller things.

Smaller Teams

Why Google Can't Build Instagram relates a story about how Larry Ellison coaxed efficiencies from teams:

If a team wasn't productive, he'd come every couple of weeks and say "let me help you out." What did he do? He took away another person until the team started shipping and stopped having unproductive meetings.

This turns mythical man-month on its head. I wonder if I should try this in my project courses?

Smaller Scope

In the same blog entry, Scoble says:

[Instagram] actually started out as a service that did a lot more than just photographs. But, they learned they couldn't complete such a grand vision and do it well. So they kept throwing out features.

If you can't do all that you dreamed of doing, do less -- and do it well. Articles like this one imply that, as organizations get larger and more visible, they lose the ability to reduce scope and focus quality on a smaller project. I'm not sure they lose their ability so much as their will.

Smaller Promises

Paul Dyson tells a familiar story about the conflict between what a name comes to connote and the actions that are what it should denote:

I recently sat in front of a customer's project manager -- a very smart and reasonable person -- and accidentally used the A-word ["agile"] when describing how we were going to deliver our product and required customisations to them, and they sneered.

They actually snorted in disgust.

When I then explained we would get them live and using the base product quickly, followed by weekly incremental improvements with regular reviews and plenty of opportunity for rework they were very happy.

But they didn't see any connection between the two things.

The hype that seems inevitably to smother so many great ideas in the software world has, for many parts of our world, made "agile" meaningless at best and risible at worst. That's too bad, because when we ruin good words we lose a useful avenue for communication.

Later in the same piece, Dyson offers his solution:

... it's not about being agile/Agile or achieving agility, or being lean/Lean and efficient. It's about delivering software. And I figure the best way to champion that is actually just to get better at doing it.

I love those last two sentences. The best way to show people the value of patterns or TDD or refactoring or almost any practice is to do it. It's about delivering software.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

November 11, 2010 8:00 AM

A Gresham's Law for Software

Recently, Kent Beck tweeted:

cleaning up junit in preparation for 4.9 release with @dsaff. why do bad design decisions spread faster than good ones?

I immediately thought of Gresham's Law from economics, which is commonly expressed as "bad money drives good money out of circulation". That sounds like what Kent is saying: bad design decisions drive good ones out of our code.

In reality, the two ideas are not alike. Gresham's Law refers to a human behavior we can all understand. Suppose we have two coins denominated as a worth one dollar. The first coin is made of gold, a rare metal of enduring social and economic value. The second is made of nickel, a common metal not valued by the people using the coins. Under these conditions, people will tend to hoard the gold coins and use the nickel coins in trade. The result is that, eventually, there will be few or no gold coins in circulation. Hence the aphorism: "bad money drives good money out of circulation".

(Sir Thomas Gresham, a financial agent at the time of Queen Elizabeth I, was not the first person to note this behavior. According to Wikipedia, Aristophanes remarked on the phenomenon in his play "The Frogs", at the end of the 5th century BC.)

That's not what is happening in JUnit or other software systems. Kent and his partners aren't hoarding good design decisions and using bad ones in their place, in order to benefit later from having the good decisions at hand. Good design decisions have value only when they are deployed. They are good only in a context where they balance forces in a pleasing or supportive way. "Spending" bad design decisions in code doesn't get rid of them; it requires that we live with them every time we touch the code!

So, equating the phenomenon that Kent described with Gresham's Law would be to misuse the law. If I did so, I wouldn't be alone. Robert Mundell discusses faulty renderings of the principle in an academic paper. It wouldn't even be the first time I made the mistake. I remember vividly the night I took a midterm exam in my undergrad macroeconomics class. I misstated Gresham's Law in one of my responses. My instructor was wondering around the room. He saw my answer, leaned over, and whispered into my ear that I should think about that question again. I did and was able to correct my answer. (That guy was a way cool teacher, and not just for helping me out on the exam.)

When I saw Kent's tweet, I did not make that mistake again. I answered his question with "a perverse malformation of Gresham's Law?" John Mitchell offered his own colorful phrase: viral toxicity. That is almost certainly a better reflection of the phenomenon than mine, yet the ring of "the bad drives out the good" still appeals to me.

I think Kent's question is worth thinking about some more. Bad design does seem to infect other parts of the system and spread, by requiring us to deform other code to make it work well with the bad code, to fit with the bad structures we've already created. Perhaps Viral Toxicity is a sort of Gresham's Law for software, a phenomenon that developers need to be aware of and guard against. Maybe if we talk about the viral toxicity of bad design, other people will understand better the value and even necessity of regular refactoring!


Posted by Eugene Wallingford | Permalink | Categories: Software Development

November 03, 2010 2:12 PM

Ideas from Readers on Recent Posts

A few recent entries have given rise to interesting responses from readers. Here are two.

Fat Arrows

Relationships, Not Characters talked about how the most important part of design often lies in the space between the modules we create, whether objects or functions, not the modules themselves. After reading this, John Cook reminded me about an article by Thomas Guest, Distorted Software. Near the end of that piece, which talks about design diagrams, Guest suggests that the arrows in application diagrams should be larger, so that they would be proportional to the time their components take to develop. Cook says:

We typically draw big boxes and little arrows in software diagrams. But most of the work is in the arrows! We should draw fat arrows and little boxes.

I'm not sure that would make our OO class diagrams better, but it might help us to think more accurately!

My Kid Could Do That

Ideas, Execution, and Technical Achievement wistfully admitted that knowing how to build Facebook or Twitter isn't enough to become a billionaire. You have to think to do it. David Schmüdde mentioned this entry in his recent My Kid Could Do That, which starts:

One of my favorite artists is Mark Rothko. Many reject his work thinking that they're missing some genius, or offended that others see something in his work that they don't. I don't look for genius because genuine genius is a rare commodity that is only understood in hindsight and reflection. The beauty of Rothko's work is, of course, its simplicity.

That paragraph connects with one of the key points of my entry: Genius is rare, and in most ways irrelevant to what really matters. Many people have ideas; many people have skills. Great things happen when someone brings these ingredients together and does something.

Later, he writes:

The real story with Rothko is not the painting. It's what happens with the painting when it is placed in a museum, in front of people at a specific place in the world, at a specific time.

In a comment on this post, I thanked Dave, and not just because he discusses my personal reminiscence. I love art but am a novice when it comes to understanding much of it. My family and I saw an elaborate Rothko exhibit at the Smithsonian this summer. It was my first trip to the Smithsonian complex -- a wonderful two days -- and my first extended exposure to Rothko's work. I didn't reject his art, but I did leave the exhibit puzzled. What's the big deal?, I wondered. Now I have a new context in which to think about that question and Rothko's art. I didn't expect the new context to come from a connection a reader made to my post on tech start-up ideas that change the world!

I am glad to know that thinkers like Schmüdde are able to make connections like these. I should note that he is a professional artist (both visual and aural), a teacher, and a recovering computer scientist -- and a former student of mine. Opportunities to make connections arise when worlds collide.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Patterns, Personal, Software Development

November 02, 2010 11:00 AM

Relationships, Not Characters

Early in his book "Impro", Keith Johnstone quotes playwright Edward Bond to the effect:

Drama is is about relationships, not about characters.

This immediately brought to mind Alan Kay's insistence that object-oriented programmers too often focus so much on the objects in their programmers that they lose sight of something more important: the space between the objects. A few years ago, I wrote about this idea in an entry called Software in Negative Space. It remains one of my most-read articles.

The secret to good OO design is in the ma, the web of relationships that make up a complex system, not in the objects themselves.

I think this is probably true of good design in any style, because it is really about how complex systems can manage and use encapsulation. The very best OO design patterns show us how multiple objects interact via message passing to resolve a thorny set of forces. The individual objects don't solve the problem; the solution lies in their interfaces and delegation of responsibility. We need to think about our designs at that level, too.

Now that functional programming is receiving so much mainstream attention, this is a good time to think about when and how good functional design is about relationships, not (just) functions. A combinator is an example: the particular functions are not as important as they way they hook together to solve a bigger problem. Designing functions in this style requires thinking more about the interfaces that expose abstractions to the world, and how other modules use them as service, and less about their implementation. Relationships.


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

October 30, 2010 1:01 PM

The Time is Right for Functional Design Patterns

Back in 1998, I documented some of the ideas that I used to teach functional programming in Scheme. The result was the beginnings of a small pattern language I called Roundabout. When I workshopped this paper at PLoP, I had a lot of fun, but it was a challenge. My workshop consisted of professional developers, most working in Java, with little or no experience in Scheme. Worse, many had been exposed to Lisp as undergraduates and had had negative experiences. Even though they all seemed open to my paper, subconsciously their eyes and ears were closed.

We gathered over lunch so that I could teach a quick primer on how to read Scheme. The workshop went well, and I received much useful feedback.

Still, that wasn't the audience for Roundabout. They were are OO programmers. To the extent they were looking for patterns to use, they were looking for GoF-style OO patterns, C++, Java, and enterprise patterns. I had a hard time finding an audience for Roundabout. Most folks in the OO world weren't ready yet; they were still trying to learn how to do OOD and OOP really well. I gave a short talk on how I use Roundabout in class at an ICFP workshop, but the folks there already knew these patterns well, and most were beyond the novice level at which they live. Besides, the functional programming world wasn't all that keen on the idea of patterns at all, not patterns in the style of Christopher Alexander.

Fast forward to 2010. We now have Scala and Clojure on the JVM. A local developer I know is working hard to wrap his head around FP. Last week, he sent me a link to an InfoQ talk by Aino Corry on Functional Design Patterns. The talk is about patterns more generally, what they are and how GoF patterns fit in the functional programming world. At about the 19:00 mark, she mentions... Roundabout! My colleague is surprised to hear my name and tweets his excitement.

My work on functional design patterns is resurfacing. Why? The world is changing. With Scala and Clojure poised to make noise in the Java enterprise world, functional programming is here. People are talking about Scheme and especially Haskell again. Functional programming is trendy now, with famous OO consultants talking it up and making the rounds at conferences and workshops giving talks about how important it is. (Some folks have been saying that for a while...)

The software patterns "movement" grew out of a need felt by many programmers around the world to learn how to do OO design and programming. Most had been weaned on traditional procedural programming and built up years of experience programming in that style, only to find that their experience didn't transfer smoothly into the OO world. Patterns were an ideal vehicle for documenting OO expertise and communicating it to programmers as they learned the new style.

We now face a similar transition in industry and even academia, as languages like Scala and Clojure begin to change how professionals build their systems. They are again finding that their experience -- now with OO -- does not transfer into the functional world without a few hitches. What we need now are papers that document functional design and programming patterns, both at the most basic level (like Roundabout) and at a higher level (like GoF). We have some starting points from which to begin the journey. There has been some good work done on refactoring functional-style programs, and refactoring is a complement to patterns.

This is a great opportunity for experienced functional programmers to teach their style to a large new audience that now has incentive to learn it. This is also a great opportunity to demonstrate again the value of the software pattern as a form for documenting and teaching how to build things. The question is, what to do next.


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

October 26, 2010 4:58 PM

Mindset, Faith, and Code Retreats

If I were more honest with myself, I would probably have to say something like this more often:

He also gave me the white book, XP Explained, which I dismissed outright as rubbish. The ideas did not fit my mental model and therefore they were crap.

Like many people, I am too prone to impose my way of thinking and working on everything. Learning requires changing how I think and do, and that can only happen when I don't dismiss new ideas as wrong.

I found that passage in Corey's Code Retreat, a review of a code retreat conducted by Corey Haines. The article closes with the author's assessment of what he had learned over the course of the day, including this gem:

... faith is a necessary component of design ...

This is one of the hardest things for beginning programmers to understand, and that gets in the way of their learning. Without much experience writing code, they often are overwhelmed by the uncertainty that comes with making anything that is just beyond their experience. And that is where the most interesting work lies: just beyond our experience.

Runners training for their first marathon often feel the same way. But experience is no antidote for this affliction. Despair and anger are common emotions, and they sometimes strike us hardest when we know how to solve problems in one way and are asked to learn a new way to think and do.

Some people are naturally optimistic and open to learning. Others have cultivated an attitude of openness. Either way, a person is better prepared to have faith that they will eventually get it. Once we have experience, our faith is buttressed by our knowledge that we probably will reach a good design -- and that, if we don't, we will know how to respond.

This article testifies to the power of a reflective code retreat led by a master. After reading it, I want to attend one! I think this would be a great thing for our local software community to try. For example, a code retreat could help professional programmers grok functional programming better than just reading books about FP or about the latest programming language.

~~~~

The article also opens with a definition of engineering I had not seen before:

... the strategy for causing the best change in a poorly understood situation within the available resources ...

I will think about it some more, but on first and second readings, I like this.


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

October 21, 2010 8:50 AM

Strange Loop Redux

StrangeLoop 2010 logo

I am back home from St. Louis and Des Moines, up to my next in regular life. I recorded some of my thoughts and experiences from Strange Loop in a set of entries here:

Unlike most of the academic conferences I attend, Strange Loop was not held in a convention center or in a massive conference hotel. The primary venue for the conference was the Pageant Theater, a concert nightclub in the Delmar Loop:

The Pageant Theater

This setting gave the conference's keynotes something of an edgy feel. The main conference lodging was the boutique Moonrise Hotel a couple of doors down:

The Pageant Theater

Conference session were also held in the Moonrise and in the Regional Arts Commission building across the street. The meeting rooms in the Moonrise and the RAC were ordinary, but I liked being in human-scale buildings that had some life to them. It was a refreshing change from my usual conference venues.

It's hard to summarize the conference in only a few words, other than perhaps to say, "Two thumbs up!" I do think, though, that one of the subliminal messages in Guy Steele's keynote is also a subliminal message of the conference. Steele talked for half an hour about a couple of his old programs and all of his machinations twenty-five or forty years to make them run in the limited computing environments of those days. As he went to all the effort to reconstruct the laborious effort that went into those programs in the first place, the viewer can't help but feel that the joke's on him. He was programming in the Stone Age!

But then he gets to the meat of his talk and shows us that how we program now is the relic of a passing age. For all the advances we have made, we still write code that transitions from state to state to state, one command at a time, just like our cave-dwelling ancestors in the 1950s.

It turns out that the joke is on us.

The talks and conversations at Strange Loop were evidence that one relatively small group of programmers in the midwestern US are ready to move into the future.


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

October 16, 2010 9:09 AM

Strange Loop, Day 2 Afternoon

After eating some dandy deep-dish BBQ chicken at Pi Pizzeria with the guys from T8 Webware (thanks, Wade!), I returned for a last big run of sessions. I'll save the first session for last, because my report of it is the longest.

Android Squared

I went to this session because so many of my students want me to get down in the trenches with phone programming. I saw a few cool tools, especially RetroFit, a new open-source framework for Android. There are not enough hours in a day for me to explore every tool out there. Maybe I can have a student do an Android project.

Java Puzzlers

And I went to this session because I am weak. I am a sucker for silly programming puzzles, especially ones that take advantage of the dark corners of our programming languages. This session did not disappoint in this regard. Oh, the tortured code they showed us! I draw from this experience a two-part moral:

  1. Bad programmers can write really bad code, especially in a complex language.
  2. A language that is too complex makes bad programmers of us all.

Brian Marick on Outside-In TDD

Marick demoed a top-down | outside-in style of TDD in Clojure using Midje, his homebrew test package. This package and style make heavy use of mock objects. Though I've dinked around a bit in Scala, I've done almost nothing in Clojure, so I'll have to try this out. The best quote of the session echoed a truth about all programming: You should have no words in your test that are not specifically about the test.

Douglas Crockford, Open-Source Heretic

Maybe my brain was fried by the end of the two days, or perhaps I'm simply not clever enough. While I able to chuckle several times through this closing keynote, I never saw the big picture or the point of the talk. There were plenty of interesting, if disconnected, stories and anecdotes. I enjoyed Crockford's coverage of several historical mark-up languages, including Runoff and Scribe. (Runoff was the forebear of troff, a Unix utility I used throughout grad school -- I even produced my wedding invitations using it! Fans of Scribe should take a look at Scribble, a mark-up tool built-on top of Racket.) He also told an absolutely wonderful story about Grace Murray Hopper's A-0, the first compiler-like tool and likely the first open-source software project.

Panel on the Future of Languages

Panels like this often don't have a coherent summary. About all I can do is provide a couple of one-liners and short answers to a couple of particularly salient questions.

Joshua Bloch: Today's patterns are tomorrow's language features. Today's bugs are tomorrow's type system features.

Douglas Crockford: Javascript has become what Java was meant to be, the language that runs everywhere, the assembly language of the web.

Someone in the audience asked, "Are changes in programming languages driven by academic discovery or by practitioner pain?" Guy Steele gave the best answer: The evolution of ideas is driven by academics. Uptake is driven by practitioner needs.

So, what is the next big thing in programming languages? Some panelists gave answers grounded in today's problems: concurrency, a language that could provide and end-to-end solution for the web, and security. One panelists offered laziness. I think that laziness will change how many programmers think -- but only after functional programming has blanketed the mainstream. Collectively, several panelists offered variations of sloppy programming, citing as early examples Erlang's approach to error recovery, NoSQL's not-quite-data consistency, and Martin Rinard's work on acceptability-oriented computing.

The last question from the audience elicited some suggestions you might be able to use. What language, obscure or otherwise, should people learn in order to learn the language you really want them to learn? For this one, I'll give you a complete list of the answers:

  • Io. (Bruce Tate)
  • Rebol. (Douglas Crockford)
  • Forth. Factor. (Alex Payne)
  • Scheme. Assembly. (Josh Bloch)
  • Clojure. Haskell. (Guy Steele)

I second all of these suggestions. I also second Steele's more complete answer: Learn any three languages you do not know. The comparisons and contrasts among them will teach you more than any one language can.

Panel moderator Ted Neward closed the session with a follow-up question: "But what should the Perl guys learn while they are waiting for Perl 6?" We are still waiting for the answer.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

October 15, 2010 11:46 PM

Strange Loop, Day 2 Morning

Perhaps my brain is becoming overloaded, or I have been less disciplined in picking talks to attend, or the slate of sessions for Day 2 is less coherent than Day 1's. But today has felt scattered, and so far less satisfying than yesterday. Still, I have had some interesting thoughts.

Billy Newport on Enterprise NoSQL

This was yet another NoSQL talk, but not, because it was different than the preceding ones at the conference. This talk was not about any particular technologies. It was about mindsets.

Newport explained that NoSQL means not only SQL. These two general approaches to data storage offer complementary strengths and weaknesses. This means that they are best used in different contexts.

I don't do enough programming for big data apps to appreciate all the details of this talk. Actually, I understood most of the basic concepts, but they soon starting blurring in my mind, because I don't have personal experience on which to hang them. A few critical points stood out:

  • In the SQL world, the database is the "system of record" for all data, so consistency is a given. In the NoSQL world, having multiple systems of record is normal. In order to ensure consistency, the application uses business rules to bring data back into sync. This requires a big mind shift for SQL guys.

  • In the SQL world, the row is a bottleneck. In the NoSQL world, any node can handle the request. So there is not a bottleneck, which means the NoSQL approach scales transparently. J But see the first bullet.

These two issues are enough to see one of Newport's key points. The differences between the two worlds is not only technical but also cultural. SQL and NoSQL programmers use different vocabulary and have different goals. Consider that "in NoSQL, 'query' is a dirty word". NoSQL programmers do everything they can to turn queries into look-ups. For the SQL programmer, the query is a fundamental concept.

The really big idea I took away from this talk is that SQL and NoSQL solve different problems. The latter optimizes for one dominant question, while the former seeks to support an infinite number of questions. Most of the database challenges facing NoSQL shops boil down to this: "What happens if you ask a different question?"

Dean Wampler on Scala

The slot in which this tutorial ran was longer than the other sessions at the conference. This allowed Wampler to cover a lot of details about Scala. I didn't realize how much of an "all but the kitchen sink" language Scala is. It seems to include just about every programming language feature I know about, drawn from just about every programming language I know about.

I left the talk a bit sad. Scala contains so much. It performs so much syntactic magic, with so many implicit conversions and so many shortcuts. On the one hand, I fear that large Scala programs will overload programmers' minds the way C++ does. On the other, I worry that its emphasis on functional style will overload programmers' minds the way Haskell does.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

October 15, 2010 12:34 PM

Guy Steele's Own Strange Loop

The last talk of the afternoon of Day 1 was a keynote by Guy Steele. My notes for his talk are not all that long, or at least weren't when I started writing. However, as I expected, Steele presented a powerful talk, and I want to be able to link directly to it later.

Steele opened with a story about a program he wrote forty years ago, which he called the ugliest program he ever wrote. It fit on a single punch card. To help us understand this program, he described in some detail the IBM hardware on which it ran. One problem he faced as a programmer is that the dumps were undifferentiated streams of bytes. Steele wanted line breaks, so he wrote an assembly language program to do that -- his ugliest program.

Forty years later, all he has is the punch card -- no source. Steele's story then turned into CSI: Mainframe. He painstakingly reverse-engineered his code from punches on the card. We learned about instruction format, data words, register codes... everything we needed to know how this program managed to dump memory with newlines and fit on a single card. The number of hacks he used, playing on puns between op codes and data and addresses, was stunning. That he could resurrect these memories forty years later was just as impressive.

I am just old enough to have programmed assembly for a couple of terms on punch cards. This talk brought back memories, even how you can recognize data tables on a card by the unused rows where there are no op codes. What a wonderful forensics story.

The young guys in the room liked the story, but I think some were ready for the meet of the talk. But Steele told another, about a program for computing sin 3x on a PDP-11. To write this program, Steele took advantage of changes in the assembly languages between the IBM mainframe and the PDP-11 to create more readable code. Still, he had to use several idioms to make it run quickly in the space available.

These stories are all about automating resource management, from octal code to assemblers on up to virtual memory and garbage collection. These techniques let the programmer release concerns about managing memory resources to tools. Steele's two stories demonstrate the kind of thinking that programmers had to do back in the days when managing memory was the programmer's job. It turns out that the best way to think about memory management is not to think about it at all.

At this point, Steele closed his own strange loop back to the title of his talk. His thesis is this: the best way to think about parallel programming is not to have to.

If we program using a new set of idioms, then parallelism can be automated in our tools. The idioms aren't about parallelism; they are more like functional programming patterns that commit the program less to underlying implementation.

There are several implications of Steele's thesis. Here are two:

  • Accumulators are bad. Divide and conquer is good.

  • Certain algebraic properties of our code are important. Programmers need to know and preserve them in then code they write.

Steele illustrated both of these implications by solving an example problem that would fit nicely in a CS1 course: finding all the words in a string. With such a simple problem, everyone in the room has an immediate intuition about how to solve it. And nearly everyone's intuition produces a program using accumulators that violates several important algebraic properties that our code might have.

One thing I love about Steele's talks: he grounds ideas in real code. He developed a complete solution to the problem in Fortress, the language Steele and his team have been creating at Sun/Oracle for the last few years. I won't try to reproduce the program or the process. I will say this much. One, the process demonstrated a wonderful interplay between functions and objects. Two, in the end, I felt like we had just used a process very similar to the one I use when teaching students to create this functional merge sort function:

    (define mergesort
       (lambda (lst)
          (merge-all (map list lst))))

Steele closed his talk with the big ideas that his programs and stories embody. Among the important algebraic properties that programs should have whenever possible are ones we all learned in grade school, explicitly or implicitly. Though they may still sound scary, they all have intuitive common meanings:

  • associative -- grouping don't matter
  • commutative -- order doesn't matter
  • idempotent -- duplicates don't matter
  • identity -- this value doesn't matter
  • zero -- other values don't matter

Steele said that "wiggle room" was the key buzzword to take away from his talk. Preserving invariants of these algebraic properties give the compiler wiggle room to choose among alternative ways to implement the solution. In particulars, associativity and commutativity give the compiler wiggle room to parallelize the implementation.

(Note that the merge-all operation in my mergesort program satisfies all five properties.)

One way to convert an imperative loop to a parallel solution is to think in terms of grouping and functions:

  1. Bunch mutable state together as a state "value".
  2. Look at the loop as an application of one or more state transformation functions.
  3. Look for an efficient way to compose these transformation functions into a single function.

The first two steps are relatively straightforward. The third step is the part that requires ingenuity!

In this style of programming, associative combining operators are a big deal. Creating new, more diverse associative combining operators is the future of programming. Creating new idioms -- the patterns of programs written in this style -- is one of our challenges. Good programming languages of the future will provide, encourage, and enforce invariants that give compilers wiggle room.

In closing, Steele summarized our task as this: We need to do for processor allocation what garbage collection did for memory allocation. This is essential in a world in which we have parallel computers of wildly different sizes. (Multicore processors, anyone?)

I told some of the guys at the conference that I go to hear Guy Steele irrespective of his topic. I've been fortunate enough to be in a small OOPSLA workshop on creativity with Steele, gang-writing poetry and Sudoku generators, and I have seen him speak a few times over the years. Like his past talks, this talk makes me think differently about programs. It also crystallizes several existing ideas in a way that clarifies important questions.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

October 08, 2010 3:53 PM

Strange Loops

StrangeLoop 2010 logo

As busy as things are here with class and department duties, I am excited to be heading to StrangeLoop 2010 next week. The conference description sounds like it is right up my alley:

Strange Loop is a developer-run software conference. Innovation, creativity, and the future happen in the magical nexus "between" established areas. Strange Loop eagerly promotes a mix of languages and technologies in this nexus, bringing together the worlds of bleeding edge technology, enterprise systems, and academic research.

Of particular interest are new directions in data storage, alternative languages, concurrent and distributed systems, front-end web, semantic web, and mobile apps.

One of the reasons I've always liked OOPSLA is that it is about programming. It also mixes hard-core developers with academics, tools with theory. Unfortunately, I'll be missing OOPSLA (now called SPLASH) again this year. I hope that StrangeLoop will inspire me in a similar way. The range of technologies and speakers on the program tells me it probably will.

2010 Des Moines Marathon logo

The day after I return from St. Louis, I hit the road again for the Des Moines Marathon, where I'll run strange loops of a different sort. My training has gone pretty well since the end of July, with mileage and speed work hitting targets I set back in June. Before my taper, I managed three weeks of 50 miles or more, including three 20+ mile long runs. Will that translate into a good race day? We never know. But I'm looking forward to the race, as well as the Saturday expo and dinner with a good buddy the night before.

If nothing else, the marathon will give me a few hours to reflect on what I learn at StrangeLoop and to think about what I will do with it!


Posted by Eugene Wallingford | Permalink | Categories: Running, Software Development

September 22, 2010 4:38 PM

What Agile Isn't

Traffic on the XP mailing list has been heavy for the last few weeks, with a lot of "meta" discussion spawned by messages from questioners seeking a firmer understanding of this thing we call "agile software development". I haven't had time to read even a small fraction of the messages, but I do check in occasionally. Often, I'll target in on comments from specific writers whose expertise and experience I value. Other times, I'll follow a sub-sub-plot to see a broader spectrum of ideas.

Two recent messages really stood out to me as important signposts in the long-term conversation about agile software development. First, Charlie Poole reminded everyone that Agile Isn't a "Thing".

The ongoing thread about whether is always/sometimes/not always/never/ whatever "right" for a given environment seems to me to be missing something rather important. It seems to be based on the assumption that "agile" is some particular thing that we can talk about unambiguously.

It isn't.

If you come to the "agile" community looking for one answer to any question, or agreement on specific practices, or a dictum that developers or managers can use to change minds, you'll be disappointed. It's much more nebulous than that:

Agile is a set of values. They fit anywhere that those values are respected, including places where folks are trying to move the company culture away from antithetical values and towards those of agile.

If you are working with a group of people who share these values, or who are open to them, then you can "do agile" by looking for ways to bring your group's practices more in alignment with your values. You can accomplish this in almost any environment. But to get specific about agile, Charlie reminds us, you probably have to shift the conversation to specific approaches to agile development, and even specific practices.

When I use the term "agile", I try not to use it solo. I like to say "agile software development" or simply "agile development". Software configuration management guru Brad Appleton wrote the second post to catch my eye and goes a step beyond "Agile Isn't a 'Thing'" to the root of the issue: "agile" is an adjective!

"Agile" is something that you are (or are not), not something that you "do".

So simple. Thanks, Brad.

I can talk about "agility" as a noun, where it is the quality attained by "being agile". I can talk about "agile" a modifier of a noun/thing, even if the "thing" it is modifying is a set of values, principles, beliefs, behaviors, etc.

He doesn't stop there, though, for which I'm glad. You can try to develop software in an agile way -- with an openness to change, typically using short iterations and continuous feedback -- and thus try to be more agile. You can adopt a set of values, but if you don't change what you do then you probably won't be any more agile.

I also liked that Brad points out it's not reasonable to expect to realize the promise developing software in an agile way if one ignores the premise of the agile approaches. For example, executing a certain method or set of practices won't enable you to respond to change with facility unless you also take actions that keep the cost of change low and pay attention to whether or not these actions are succeeding. Most importantly, "agile" is not a synonym for happiness or success. "Being agile" may be a way to be happier as a developer or person, but we should not confuse the goal of "being agile" with the goal of being happy or successful or happy.

The title of this entry, "What Agile Isn't", ought to sound funny, because it isn't entirely grammatically correct. If we quote the "Agile", at least then we could be honest in indicating that we are talking about a word.

Don't worry too much about whether you fit someone else's narrow definition of "agile". Just keep trying to get better by choosing -- deliberately and with care -- actions and practices that will move you in the direction of your goal. The rest will take care of itself.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

September 20, 2010 4:28 PM

Alan Kay on "Real" Object-Oriented Programming

In Alan Kay's latest comment-turned-blog entry, he offers thoughts in response to Moti Ben-Ari's CACM piece about object-oriented programming. Throughout, he distinguishes "real oop" from what passes under the term these days. His original idea of object-oriented software is really quite simple to express: encapsulated modules all the way down, with pure messaging. This statement boils down to its essence many of the things he has written and talked about over the years, such as in his OOPSLA 2004 talks.

This is a way to think about and design systems, not a set of language features grafted onto existing languages or onto existing ways of programming. He laments what he calls "simulated data structure programming", which is, sadly, the dominant style one sees in OOP books these days. I see this style in nearly every OOP textbook -- especially those aimed at beginners, because those books generally start with "the fundamentals" of the old style. I see it in courses at my university, and even dribbling into my own courses.

One of the best examples of an object-oriented system is one most people don't think of as a system at all: the Internet:

It has billions of completely encapsulated objects (the computers themselves) and uses a pure messaging system of "requests, not commands", etc.

Distributed client-server apps make good examples and problems in courses on OO design precisely because they separate control of the client and the server. When we write OO software in which we control both sides of the message, it's often too tempting to take advantage of how we control both objects and to violate encapsulation. These violations can be quite subtle, even when we take into account idioms such as access methods and the Law of Demeter. To what extent does one component depend on how another component does its job? The larger the answer, the more coupled the components.

Encapsulation isn't an end unto itself, of course. Nor are other features of our implementation:

The key to safety lies in the encapsulation. The key to scalability lies in how messaging is actually done (e.g., maybe it is better to only receive messages via "postings of needs"). The key to abstraction and compactness lies in a felicitous combination of design and mathematics.

I'd love to hear Kay elaborate on this "felicitous combination of design and mathematics"... I'm not sure just what he means!

As an old AI guy, I am happy to see Kay make reference to the Actor model proposed by Carl Hewitt back in the 1970s. Hewitt's ideas drew some of their motivation from the earliest Smalltalk and gave rise not only to Hewitt's later work on concurrent programming but also Scheme. Kay even says that many of Hewitt's ideas "were more in the spirit of OOP than the subsequent Smalltalks."

Another old AI idea that came to my mind as I read the article was blackboard architecture. Kay doesn't mention blackboards explicitly but does talk about how messaging might better be if instead of an object sent messages to specific targets they might "post their needs". In a blackboard system, objects capable of satisfying needs monitor the blackboard and offer to respond to a request as they are able. The blackboard metaphor maintains some currency in the software world, especially in the distributed computing world; it even shows up as an architectural pattern in Pattern-Oriented Software Architecture. This is a rich metaphor with much room for exploration as a mechanism for OOP.

Finally, as a CS educator, I could help but notice Kay repeating a common theme of his from the last decade, if not longer:

The key to resolving many of these issues lies in carrying out education in computing in a vastly different way than is done today.

That is a tall order all its own, much harder in some ways than carrying out software development in a vastly different way than is done today.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

September 14, 2010 9:58 PM

Thinking About Things Your Users Don't Know

Recently, one of the software developers I follow on Twitter posted a link to 10 Things Non-Technical Users Don't Understand About Your Software. It documents the gap the author has noticed between himself as a software developer and the people who use the software he creates. A couple, such as copy and paste and data storage, are so basic that they might surprise new developers. Others, such concurrency and the technical jargon of software, aren't all that surprising, but developers need to keep them in mind when building and documenting their systems. One, the need for back-ups, eludes even for technical users. Unfortunately,

You can mention the need for back-ups in your documentation and/or in the software, but it is unlikely to make much difference. History shows that this is a lesson most people have to learn the hard way (techies included).

Um, yeah.

a polar leaps the chasm between ice floes

As I read this article, I began to think that it would be fun and enlightening to write a series of blog entries on the things that CS majors don't understand about our courses. I could start with ten as a target length, but I'm pretty sure that I can identify even more. As the author of the non-technical users paper points out, the value in such a list is most definitely not to demean the students or users. Rather, it is exceedingly useful for professors to remember that their students are not like them and to keep these differences in mind as they design their courses, create assignments, and talk with the students. Like almost everyone who interacts with people, we can do a better job if we understand our audience!

So, I'll be on the look-out for topics specific to CS students. If you have any suggestions, you know how to reach me.

After I finished reading the article, I looked back at the list and realized that many of these things are themselves things that CS majors don't understand about their courses. Consider especially these:

the jargon you use

It took me several years to understand just how often the jargon I used in class sounded like white noise to my students. I'm under no illusion that I now speak in the clearest vocabulary and that all my students understand what I'm saying as I say it. But I think about this often as I prepare and deliver my lectures, and I think I'm better than I used to be.

they should read the documentation

I'm used to be surprised when, on our student assessments, a student responds to the question "What could I have done better to improve my learning in this course?" with "Read the book". (Even worse, some students say "Buy the book"!) Now, I'm just saddened. I can say only so much in class. Our work in class can only introduce students to the concepts we are learning, not cover them in their entirety. Students simply must read the textbook. In upper-division courses, they may well need to read secondary sources and software documentation, too. But they don't always know that, and we need to help them know it as soon as possible.

Finally, my favorite:

the problem exists between keyboard and chair

Let me sample from the article and substitute students for users:

Unskilled students often don't realize how unskilled they are. Consequently they may blame your course (and lectures and projects and tests) for problems that are of their own making.

For many students, it's just a matter of learning that they need to take responsibility for their own learning. Our K-12 schools often do not prepare them very well for this part of the college experience. Sometimes, professors have to be sensitive in raising this topic with students who don't seem to be getting it on their own. A soft touch can do wonders with some students; with others, polite but direct statements are essential.

The author of this article closes his discussion of this topic with advice that applies quite well in the academic setting:

However, if several people have the same problem then you need to change your product to be a better fit for your users (changing your users to be a better fit to your software unfortunately not being an option for most of us).

You see, sometimes the professor's problem exists between his keyboard and his chair, too!


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

September 10, 2010 2:22 PM

Recursion, Trampolines, and Software Development Process

Yesterday I read an old article on tail calls and trampolining in Scala by Rich Dougherty, which summarizes nicely the problem of recursive programming on the JVM. Scala is a functional language, which lends itself to recursive and mutually recursive programs. Compiling those programs to run on the JVM presents problems because (1) the JVM's control stack is shallow and (2) the JVM doesn't support tail-call optimization. Fortunately, Scala supports first-class functions, which enables the programmer to implement a "trampoline" that avoids the growing the stack. The resulting code is harder to understand and so to maintain, but it runs without growing the control stack. This is a nice little essay.

Dougherty's conclusion about trampoline code being harder to understand reminded me of a response by reader Edward Coffin to my July entry on CS faculty sending bad signals about recursion. He agreed that recursion usually is not a problem from a technical standpoint but pointed out a social problem (paraphrased):

I have one comment about the use of recursion in safety-critical code, though: it is potentially brittle with respect to changes made by someone not familiar with that piece of code, and brittle in a way that makes breaking the code difficult to detect. I'm thinking of two cases here: (1) a maintainer unwittingly modifies the code in a way that prevents the compiler from making the formerly possible tail-call optimization and (2) the organization moves to a compiler that doesn't support tail-call optimization from one that did.

Edward then explained how hard it is to warn the programmers that they have just made changes to the code that invalidate essential preconditions. This seems like a good place to comment the code, but we can't rely on programmers paying attention to such comments, even that the comments will accompany the code forever. The compiler may not warn us, and it may be hard to write test cases that reliably fail when the optimization is missed. Scala's @tailrec annotation is a great tool to have in this situation!

"Ideally," he writes, "these problems would be things a good organization could deal with." Unfortunately, I'm guessing that most enterprise computing shops are probably not well equipped to handle them gracefully, either by personnel or process. Coffin closes with a pragmatic insight (again, paraphrased):

... it is quite possible that [such organizations] are making the right judgement by forbidding it, considering their own skill levels. However, they may be using the wrong rationale -- "We won't do this because it is generally a bad idea." -- instead of the more accurate "We won't do this because we aren't capable of doing it properly."

Good point. I don't suppose it's reasonable for me or anyone to expect people in software shops to say that. Maybe the rise of languages such and Scala and Clojure will help both industry and academia improve the level of developers' ability to work with functional programming issues. That might allow more organizations to use a good technical solution when it is suitable.

That's one of the reasons I still believe that CS educators should take care to give students a balanced view of recursive programming. Industry is beginning to demand it. Besides, you never know when a young person will get excited about a problem whose solution feels so right as a recursion and set off to write a program to grow his excitement. We also want our graduates to be able to create solutions to hard problems that leverage the power of recursion. We need for students to grok the Big Idea of recursion as a means for decomposing problems and composing systems. The founding of Google offers an instructive example of using inductive definition recursion, as discussed in this Scientific American article on web science:

[Page and Brin's] big insight was that the importance of a page -- how relevant it is -- was best understood in terms of the number and importance of the pages linking to it. The difficulty was that part of this definition is recursive: the importance of a page is determined by the importance of the pages linking to it, whose importance is determined by the importance of the pages linking to them. [They] figured out an elegant mathematical way to represent that property and developed an algorithm they called PageRank to exploit the recursiveness, thus returning pages ranked from most relevant to least.

Much like my Elo ratings program that used successive approximation, PageRank may be implemented in some other way, but it began as a recursive idea. Students aren't likely to have big recursive ideas if we spend years giving them the impression it is an esoteric technique best reserved for their theory courses.

So, yea! for Scala, Clojure, and all the other languages that are making recursion respectable in practice.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

September 06, 2010 12:45 PM

Empiricism, Bias, and Confidence

This morning, Mike Feathers tweeted a link to an old article by Donald Norman, Simplicity Is Highly Overrated and mentioned that he disagrees with Norman. Many software folks disagreed with Norman when he first wrote the piece, too. We in software, often being both designers and users, have learned to appreciate simplicity, both functionally and aesthetically. And, as Kent Beck suggested, products such as the iPod are evidence contrary to the claim that people prefer the appearance of complexity. Norman offered examples in support of his position, too, of course, and claimed that he has observed them over many years and in many cultures.

This seems like a really interesting area for study. Do people really prefer the appearance of complexity as a proxy for functionality? Is the iPod an exception, and if so why? Are software developers different from the more general population when it comes to matters of function, simplicity, and use?

When answering these questions, I am leery of relying on self-inspection and anecdote. Norman said it nicely in the addendum to his article:

Logic and reason, I have to keep explaining, are wonderful virtues, but they are irrelevant in describing human behavior.

He calls this the Engineer's Fallacy. I'm glad Norman also mentions economists, because much of the economic theory that drives our world was creating from deep analytic thought, often well-intentioned but usually without much evidence to support it, if any at all. Many economists themselves recognize this problem, as in this familiar quote:

If economists wished to study the horse, they wouldn't go and look at horses. They'd sit in their studies and say to themselves, "What would I do if I were a horse?"

This is a human affliction, not just a weakness of engineers and economists. Many academics accepted the Sapir-Whorf Hypothesis, which conjectures that our language restricts how we think, despite little empirical support for a claim so strong. The hypothesis affected in disciplines such as psychology, anthropology, and education, as well as linguistics itself. Fortunately, others subjected the hypothesis to study and found it lacking.

For a while, it was fashionable to dismiss Sapir-Whorf. Now, as a recent New York Times article reports, researchers have begun to demonstrate subtler and more interesting ways in which the language we speaks shapes how we think. The new theories follow from empirical data. I feel a lot more confident in believing the new theories, because we have derived them from more reliable data than we ever had for the older, stronger claim.

(If you read the Times article, you will see that Whorf was an engineer, so maybe the tendency to develop theories from logical analysis and sparse data really is more prominent in those of us trained in the creation of artifacts to solve problems...)

We see the same tendencies in software design. One of the things I find attractive about the agile world is its predisposition toward empiricism. Just yesterday Jason Gorman posted a great example, Reused Abstractions Principle. For me, software abstractions that we discover empirically have a head-start toward confident believability on the ones we design aforethought. We have seen them instantiated in actual code. Even more, we have seen them twice, so they have already been reused -- in advance of creating the abstraction.

Given how frequently even domain experts are wrong in their forecasts of the future and their theorizing about the world, how frequently we are all betrayed by our biases and other subconscious tendencies, I prefer when we have reliable data to support claims about human preferences and human behavior. A flip but too often true way to say "design aforethought" is "make up".


Posted by Eugene Wallingford | Permalink | Categories: General, Software Development

August 31, 2010 7:18 PM

Notes from a Master Designer

Someone tweeted recently about a recent interview with Fred Brooks in Wired magazine. Brooks is one of the giants of our field, so I went straight to the page. I knew that I wanted to write something about the interview as soon as I saw this exchange, which followed up questions about how a 1940s North Carolina schoolboy ended up working with computers:

Wired: When you finally got your hands on a computer in the 1950s, what did you do with it?

Brooks: In our first year of graduate school, a friend and I wrote a program to compose tunes. The only large sample of tunes we had access to was hymns, so we started generating common-meter hymns. They were good enough that we could have palmed them off to any choir.

It never surprises me when I learn that programmers and computer scientists are first drawn to software by a desire to implement creative and intelligent tasks. Brooks was first drawn to computers by a desire to automatic data retrieval, which at the time must have seemed almost as fantastic as composing music. In an Communications of the ACM interview printed sometime last year, Ed Feigenbaum called AI the "manifest destiny" of computer science. I often think he is right. (I hope to write about that interview soon, too.)

But that's not the only great passage in Brooks's short interview. Consider:

Wired: You say that the Job Control Language you developed for the IBM 360 OS was "the worst computer programming language ever devised by anybody, anywhere." Have you always been so frank with yourself?

Brooks: You can learn more from failure than success. In failure you're forced to find out what part did not work. But in success you can believe everything you did was great, when in fact some parts may not have worked at all. Failure forces you to face reality.

As an undergrad, I took a two-course sequence in assembly language programming and JCL on an old IBM 370 system. I don't know how much the JCL on that machine had advanced beyond Brooks's worst computer programming language ever devised, if it had at all. But I do know that the JCL course gave me a negative-split learning experience unlike any I had ever had before or have had since. As difficult as that was, I will be forever grateful for Dr. William Brown, a veteran of the IBM 360/370 world, and what he taught me that year.

There are at least two more quotables from Brooks that are worth hanging on my door some day:

Great design does not come from great processes; it comes from great designers.

Hey to Steve Jobs.

The insight most likely to improve my own work came next:

The critical thing about the design process is to identify your scarcest resource.

This one line will keep me on my toes for many projects to come.

If great design comes from great designers, then how can the rest of us work toward the goal of becoming a great designer, or at least a better one?

Design, design, and design; and seek knowledgeable criticism.

Practice, practice, practice. But that probably won't be enough. Seek out criticism from thoughtful programmers, designers, and users. Listen to what they have to say, and use it to improve your practice.

A good start might be to read this interview and Brooks's books.


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

August 26, 2010 9:39 PM

Thinking about Software Development and My Compilers Course

Our semester is underway. I've had the pleasure of meeting my compilers course twice and am looking forward to diving into some code next week. As I read these days, I am keenly watching for things I can bring into our project, both the content of defining and interpreting language and the process of student teams writing a compiler. Of course, I end up imposing this viewpoint on whatever I read! Lately, I've been seeing a lot that makes me think about the development process for the semester.

Greg Wilson recently posted three rules for for supervising student programming projects. I think these rules are just as useful for the students as they work on their projects. In a big project course, students need to think about time, technology, and team interaction realistically in a way they. I especially like the rule, "Steady beats smart every time". It gives students hope when things get tough, even if they are smart. More importantly, it encourages them to start and to keep moving. That's the best way to make progress, no matter smart you are. (I gave similar advice during my last offering of compilers.) My most successful project teams in both the compilers course and in our Intelligent Systems course were the once who humbly kept working, one shovel of dirt at a time.

I'd love to help my compiler students develop in an agile way, to the extent they are comfortable. Of course, we don't have time for a full agile development course while learning the intricacies of language translation. In most of our project courses, we teach some project management along side the course content. This means devoting a relatively small amount of time to team and management functions. So I will have to stick to the essential core of agile: short iterations plus continuous feedback. As Hugh Beyer writes:

Everything else is there to make that core work better, faster, or in a more organized way. Throw away everything else if you must but don't trade off this core.

For the last couple of weeks, I have been thinking about ways to decompose the traditional stages of the compiler project (scanning, parsing, semantic analysis, and code generation) into shorter iterations. We can certainly implement the parser in two steps, first writing code to recognize legal programs and then adding code to produce abstract syntax. The students in my most recent offering of the compilers course also suggested splitting the code generation phase of the project into two parts, one for implementing the run-time system and one for producing target code. I like this idea, but we will have to come up with ways to test the separate pieces and get feedback from the earlier piece of our code.

Another way we can increase feedback is to do more in-class code reviews of the students' compilers as they write them. A student from the same previous course offering wrote to me only yesterday, in response to my article on learning from projects in industry, suggesting that reviews of student code would have enhanced his project courses. Too often professors show students only their own code, which has been designed and implemented to be clean and easy to understand. A lot of the most important learning happens in working at the rough edges, encountering problems that make things messy and solving them. Other students' code has to confront and solve the same problems, and reading that code and sharing experiences is a great way to learn.

I'm a big fan of this idea, of course, and have taught several of my courses using a studio style in the past. Now I just need to find a way to bring more of that style into my compilers course.


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

August 18, 2010 5:04 PM

You May Be in the Software Business

In the category programming for all, Paul Graham's latest essay explains his ideas about What Happened to Yahoo. (Like the classic Marvin Gaye album and song, there is no question mark.) Most people may not care about programming, but they ought to care about programs. More and more, the success of an organization depends on software.

Which companies are "in the software business" in this respect? ... The answer is: any company that needs to have good software.

If this was such a blind spot for an Internet juggernaut like Yahoo, imagine how big a surprise it must be for everyone else.

If you employ programmers, you may be tempted to stay within your comfort zone and treat your tech group just like the rest of the organization. That may not work very well. Programmers are a different breed, especially great programmers. And if you are in the software business, you want good programmers.

Hacker culture often seems kind of irresponsible. ... But there are worse things than seeming irresponsible. Losing, for example.

Again: If this was such a blind spot for an Internet juggernaut like Yahoo, imagine how big an adjustment it would be for everyone else.

I'm in a day-long retreat with my fellow department heads in the arts and sciences, and it's surprising how often software has come up in our discussions. This is especially true in recruitment and external engagement, where consistent communication is so important. It turns out the university is in the software business. Unfortunately, the university doesn't quite get that.


Posted by Eugene Wallingford | Permalink | Categories: General, Software Development

August 14, 2010 11:30 AM

The Tests Are For Me

Yesterday, one of my former students tweeted,

"Write a test first." But unit tests are low priority. The business wants high priority items first.

When I asked, "Is correct code a high priority?", he rephrased my question as, "Is proof of correct code a high priority?"

I knew what he meant and so dropped the exchange, sad that companies still settle for code without tests in the name of expediency. I try not to be dogmatic about writing tests with code, let alone driving the design with tests, and know there are times when not writing tests, at least now, feels okay.

But then it occurred to me. When I write tests, the tests aren't really for "them", whoever "them" might be: my bosses, my colleagues, or my users. My best test suites are the ones I write for myself. They are a part of how I write code.

When I'm not doing TDD and not writings tests in parallel with my code -- when not writing tests feels okay -- I am almost always not writing interesting code. Perhaps I know the domain so well that I can write the code with my eyes closed. Perhaps the domain does not engage me enough that I care to get into the deep flow that comes with testing, growing, and refactoring my program. If the task is dull or routine, then tests seem unnecessary, a drag.

(Perhaps, though, I especially need to write tests in these situations, to guard against producing bad code as a result of complacency and boredom!)

When I am writing code I enjoy, the tests are for me. Saying to me, "Don't take time to write tests" is like telling me not to use version control. It's like saying to me, "Don't take time to format your code properly" or "Don't bother naming your variables properly". Not writing tests seems foreign. Not writing tests is an impediment to writing code at all.

It's really not a matter of "taking time to write a test first". I write tests because that's how I write code.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

August 04, 2010 2:58 PM

Agile Moments: Metaphor as Practice, Metaphors for Practices

In the last few weeks, I've seen a few interesting metaphors related to agile development. Surprisingly, one of them was actually a metaphor, XP-style.

The Mute Button

Like many newcomers to XP, my students tend not to get the reason that "metaphor" was one of the original XP practices. I try to give examples that I've seen, but my set of examples is too small. That's one reason I was excited when some agile practitioners in industry created a new discussion list on metaphor in software. Joshua Kerievsky posted a link to a blog entry he had written about two metaphors that have helped him recently.

In one case, his company has started using the idea of a playlist for the products it sells, instead a book. In the other, which is the main theme of his entry, he extrapolates from the presence of a "mute" feature in the Twitter client Twittelator to a riff on thinking about Twitter as if it were television. There are some interesting similarities, as well as interesting differences. But it's a good example of how a salient metaphor can be a source of common experience for guiding the design of a software system.

Refactoring "Technical Debt"

A few months back, I wrote an entry on technical debt, suggesting that some technical debt might be okay to carry, so long as we incur it for investment, not consumption. Not everyone believes this, of course. I've been heartened by Kent Beck's writing over the last couple of years about his own questioning of when we might break our own rules, at least the rules as they have been calcified over time or hardened against the challenges of skeptical audiences.

Last month, Steve Freeman proposed a new picture of bad code: it isn't technical debt; it's an unhedged call option. This metaphor highlights the risk we run when we allow bad code to remain in the build. My metaphor's willingness to carry debt for investment implies a risk, too, because some investments fail deliver as hoped. Freeman's metaphor raises this risk to a more dangerous level. I like his story and think it applies quite nicely in many contexts.

Still, I'm willing to accept lower quality code in trade for something of greater value now -- as long as I keep my eye on the balance sheet and remain vigilant about the debt load I carry. If the load begins to creep higher, or if I begin to spend too many resources servicing the debt, then I want to clean the code up right now. The cost of the debt has risen above the value of the investment it bought me. One of the nice things about software is that we can make changes to improve its structure, if we are willing to spend the time doing so.

What is Refactoring?

Finally, here is a metaphor you can use to explain refactoring to people who don't get it yet: refactoring is a time machine. I'll be smarter tomorrow, more experienced, better informed about what the system I am building today should look like. That is when I should hop in the time machine and make my code look the way it ought, given what I know then. Boy, that take's a lot of pressure off trying to fake the perfect design today, when I don't know yet what it is.

(If I could travel in a blogging time machine, I might go back to last Friday, unmention the Kent Beck failing today, and find a way to use for the first time here!)


Posted by Eugene Wallingford | Permalink | Categories: Software Development

July 23, 2010 2:29 PM

Agile Moments: Values and Integrity Come Before Practices

As important as the technical practices of the agile software developer are, it is good to keep in mind that they are a means to an end. Jeff Langr and Tim Ottinger do a great job of summarizing the characteristics of agile development teams and reminding us that they are not specific practices. Ottinger boiled it down to a simple phrase in a recent discussion of this piece on the XP mailing list: "... start with the values."

Later in the same thread, Langr commented on what made teaching XP practices so frustrating:

... I am very happy now to be developing in a team doing TDD, and to not be debating daily with apathetic and/or duplicitous people who want to make excuses. You're right, you can reach the lazier folks, given enough time.... It's the sly ones who spent more time crafting excuses, instead of earnestly trying to learn, who drove me nuts.

Few people can learn something entirely new to them without making a good-faith effort. When someone pretends to make a good-faith effort but then schemes not to learn, everyone's time is wasted -- and a lot of the coach's or teacher's limited energy, too. I have been fortunate in my years teaching CS to encounter very few students who behave this way. Most do make an effort to learn, and their struggles are signs that I need to try something different. And every once in a while I run into into is honest and says outright, "I'm not going to do that." This lets us both move straight on to more productive uses of our time.

On the same theme of values and integrity, I love this line from John Cook

If the smart thing to do doesn't scale, maybe we shouldn't scale.

His entry is in part about values. When someone says that we can't treat people well "because that doesn't scale", they are doing what many managerial strategies and software development processes do to people. It also reminds me of why many in the agile development community favor small teams. Not everything that we value scales, and we value those things enough that we are willing to look for ways to work "small".


Posted by Eugene Wallingford | Permalink | Categories: Software Development

July 21, 2010 4:17 PM

Two Classic Programs Available for Study

I just learned that the Computer History Museum has worked with Apple Computer to make source code for MacPaint and QuickDraw available to the public. Both were written by Bill Atkinson for the original Mac, drawing on his earlier work for the Lisa. MacPaint was the iconic drawing program of the 1980s. The utility and quality of this one program played a big role in the success of the Mac. Andy Hertzfeld, another Apple pioneer, credited QuickDraw for the success of the Mac for its speed at producing the novel interface that defined the machine to the public. These programs were engineering accomplishments of a different time:

MacPaint was finished in October 1983. It coexisted in only 128K of memory with QuickDraw and portions of the operating system, and ran on an 8 Mhz processor that didn't have floating-point operations. Even with those meager resources, MacPaint provided a level of performance and function that established a new standard for personal computers.

Though I came to Macs in 1988 or so, I was never much of a MacPaint user, but I was aware of the program through friends who showed me works they created using it. Now we can look under the hood to see how the program did what it did. Atkinson implemented MacPaint in one 5,822-line Pascal program and four assembly language files for the Motorola 6800 totaling 3,583 lines. QuickDraw consists of 17,101 lines of Motorola 6800 assembly in thirty-seven modules.

I speak Pascal fluently and am eager to dig into the main MacPaint program. What patterns will I recognize? What design features will surprise me, and teach me something new? Atkinson is a master programmer, and I'm sure to learn plenty from him. He was working in an environment that so constrained his code's size that he had to do things differently than I ever think about programming.

This passage from the Computer History Museum piece shares a humorous story that highlights how Atkinson spent much of his time tightening up his code:

When the Lisa team was pushing to finalize their software in 1982, project managers started requiring programmers to submit weekly forms reporting on the number of lines of code they had written. Bill Atkinson thought that was silly. For the week in which he had rewritten QuickDraw's region calculation routines to be six times faster and 2000 lines shorter, he put "-2000" on the form. After a few more weeks the managers stopped asking him to fill out the form, and he gladly complied.

This reminded me of one of my early blog entries about refactoring. Code removed is code earned!

I don't know assembly language nearly as well as I know Pascal, let alone Motorola 6800 assembly, but I am intrigued by the idea of being able to study more than 20,000 lines of assembly language that work together on a common task and which also exposes a library API for other graphics programs. Sounds like great material for a student research project, or five...

I am a programmer, and I love to study code. Some people ask why anyone would want to read listings of any program, let alone a dated graphics program from more than twenty-five years ago. If you use software but don't write it, then you probably have no reason to look under this hood. But keep in mind that I study how computation works and how it solves problems in a given context, especially when it has limited access to time, space, or both.

But... People write programs. Don't we already know how they work? Isn't that what we teach CS students, at least ones in practical undergrad departments? Well, yes and no. Scientists from other disciplines often ask this question, not as a question but as an implication that CS is not science. I have written on this topic before, including this entry about computation in nature. But studying even human-made computation is a valuable activity. Building large systems and building tightly resource-constrained programs are still black arts.

Many programmers could write a program with the functionality of MacPaint these days, but only a few could write a program that offers such functionality under similar resource limitations. That's true even today, more than two decades after Atkinson and others of his era wrote programs like this one. Knowledge and expertise matter, and most of it is hidden away in code that most of us never get to see. Many of the techniques used by masters are documented either not well or not at all. One of the goals of the software patterns community is to document techniques and the design knowledge needed to use them effectively. And one of the great services of the free and open-source software communities is to make programs and their source code accessible to everyone, so that great ideas are available to anyone willing to work to find them -- by reading code.

Historically, engineering has almost always run ahead of science. Software scientists study source code in order to understand how and why a program works, in a qualitatively different way than is possible by studying a program from the outside. By doing so, we learn about both engineering (how to make software) and science (the abstractions that explain how software works). Whether CS is a "natural" science or not, it is science, and source code embodies what it studies.

For me, encountering the release of source code for programs such as MacPaint feels something like a biologist discovering a new species. It is exciting, and an invitation to do new work.

Update: This is worth an update: a portrait of Bill Atkinson created in MacPaint. Well done.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Patterns, Software Development

July 11, 2010 11:59 AM

Form Matters

While reading the July/August 2010 issue of Running Times, I ran across an article called "Why Form Matters" that struck me as just as useful for programmers as runners. Unfortunately, the new issue has not been posted on-line yet, so I can't link to the article. Perhaps I can make some of the connections for you.

For runners, form is the way our body works when we run: the way we hold our heads and arms; the way our feet strike the ground; the length and timing of our strides. For programmers, I am thinking of what we often call 'process', but also the smaller habitual practices we follow when we code, from how we engage a new feature to how and when we test our code, to how we manage our code repository. Like running, the act of programming is full of little features that just happen when we work. That is form.

The article opened with a story about a coach trying to fix Bill Rodgers' running form at a time when he was the best marathoner in the world. The result was surprising: textbook form, but lower efficiency. Rodgers changed his form to something better and became a worse runner.

Some runners take this to mean, "Don't fix what works. My form works for me, however bad it is." I always chuckle when I hear this and think, "When you are the best marathoner in the world, let's talk. Until then, you might want to consider ways that you can get better." And you can be sure that Bill Rodgers was always looking for ways that you can get better.

There are a lot of programmers who resist changing style or form because, hey, what I do works for me. But just as all top running coaches ask their pupils -- even the best runners -- work on their form, all programmers should work on their form, the practices they use in the moment-to-moment activity of writing code. Running form is sub-conscious, but so is the part of our programming practice that has the biggest effect on our productivity. These are the habits and the default answers that pop into our head as we work.

If you buy this connection between running form and programming practice, then there is a lot for programmers to learn from this article. First, what of that experiment with Bill Rodgers?

No reputable source claims that, at any one instant, significantly altering your form from what your body is used to will make you faster.

If you decide to try out a new set of practices, say, to go agile and practice XP, you probably won't be faster at the end of the day. New habits take time. The body and mind require practice and acclimation. When we work in teams to build software, we have to go through a process of acculturation. Time.

But that doesn't mean ... that the form your body naturally gravitates toward is what will make you fastest.

There are many reasons that you may have fallen into the practices you use now. The courses and instructors you had in school, the language(s) you learned first, and the programming culture cut your professional teeth in all lead you in a particular direction. You will naturally try to get better within the context of these influences.

Even when you have been working to get better, you may (in AI terms) reach a local max biased by the initial conditions on the search. So:

"... there is a difference between doing something reasonably well and maximizing performance."

Sometimes, we need a change in kind rather than yet another change in degree.

Nor does it mean that your "natural" form is in your best long-term interest.

Initial conditions really do have a huge effect on how we develop as runners. When we start running, our muscles are weak and we have little stamina. This affects our initial running form, which we then rehearse slowly over many months as we become better runners. The result is often that we now have stronger muscles, more stamina, and bad form!

The same is true for programmers, both solo and in teams. If we are bad at testing and refactoring when we start, we develop our programming skills and get better while not testing and refactoring. What we practice is what we become.

Now, consider this cruel irony faced by runners:

"This belief system that just doing it over and over is somehow going to make us better is really crazy. Longtime runners actually suffer from the body's ability to become efficient. You become so efficient that you start recruiting fewer muscle fibers to do the same exercise, and as you begin using [fewer] muscle fibers you start to get a little bit weaker. Over time, that can become significant. Once you've stopped recruiting as many fibers you start exerting too much pressure on the fibers you are recruiting to perform the same action. And then you start getting muscle imbalance injuries...."

We programmers may not have to worry about muscle imbalance injuries, but we can find ourselves putting all of our emphasis on our mastery of a small set of coding skills, which then become responsible for all facets of quality in the software we produce. There may be no checks and balances, no practices that help reinforce the quality we are trying to wring out of our coding skills.

How do runners break out of this rut, which is the result of locally maximizing performance? They do something wildly different. Elites might start racing at a different distance or even move to the mountains, where they can run on hills and at altitude. We duffers can also try a race at a new distances, which will encourage us to train differently. Or we might simply change our training regimen: add a track workout once a week, or join a running group that will challenge us in new ways.

Sometimes we just need a change, something new that will jolt us out our equilibrium and stress our system in new way. Programmers can do this, too, whether it's by learning a new language every year or by giving a whole new style a try.

"Running is the one sport where people think, 'I don't have to worry about my technique. ...' We also have a sport where people don't listen to what the top people are doing. ..."

... I can't think of one top runner in the last two decades who hasn't worked on form, either directly through technique drills, indirectly through strength work or simply by being mindful of it while running.

The best runners work on their form. So do the best programmers. You and I should, too. Of course,

It's important when discussing running form to remember that there's no "perfect" form that we should all aspire to.

Even though I'm a big fan of XP and other approaches, I know that there are almost as many reliable ways to deliver great software as there are programmers. The key for all of us is to keep getting better -- not just strengthening our strengths, which can lead to the irony of overtraining, but also finding our weaknesses and building up those muscles. If you tend toward domains and practices where up-front plans work best for you, great. Just don't forget to work on practices that can make you better. And, every once in a while, try something crazy new. You never know where that might lead you.

"... if I went out and said we're going to do functional testing on a set of people, you're going to find weaknesses in every single one of them. The body has adapted to who you are, but has the body adapted to the best possible thing you can offer it? No."

Runners owe it to their bodies to try to offer them the best form possible. Programmers owe it to themselves, their employers, and their customers to try to find the best techniques and process for writing code. Sometimes, that requires a little hill climbing in the search, jumping off into some foreign territory and seeing how much better we can get form there. For runners, this may literally be hill climbing!

After the opening of the Running Times article, it turned to discussion of problems and techniques very specific to running. Even I didn't want to overburden my analogy by trying to connect those passages to software development. But then the article ended with a last bit of motivation for skeptical runners, and I think it's perfect for skeptical programmers, too:

If you're thinking, "That's all well and good for college runners and pros who have all day for their running, but I have only an hour a day total for my running, so I'm better off spending that time just getting in the miles," [Pete] Magill has an answer for you.

"... if you have only an hour a day to devote to your running, the first thing you've got to do is learn to run. If you bring bad form into your running, all you're going to be doing for that hour a day is reinforcing bad form. ..."

"A lot of people waste far more time being injured from running with muscle imbalances and poorly developed form than they do spending time doing drills or exercises or short hills or setting aside a short period each week to work on form itself."

Sure, practicing and working to get better is hard and takes time. But what is the alternative? Think about all, the years, days, and minutes you spend making software. If you do it poorly -- or even well, but less efficiently than you might -- how much time are you wasting? Practice is an investment, not a consumable.

We programmers are not limited to improving our form by practicing off-line. We can also change what we do on-line: we can write a test, take a short step, and refactor. We can speed up the cycle between requirement and running code, learn from the feedback we get -- and get better at the same time.

The next time you are writing code, think about your form. Surprise yourself.


Posted by Eugene Wallingford | Permalink | Categories: Running, Software Development

June 30, 2010 5:17 PM

Changing Default Actions

Learning to do test-driven design requires a big shift in mindset for many developers. I was impressed with how well the students in my recent agile development course took to the idea of writing tests first. Even the most skeptical students seemed willing to go along with the group in using tests to specify the code they needed to write. Other agile practices, such as pair programming and communal development, helped to support all of the students, willing or skeptical, to move in the right direction.

My friend Steve Berczuk suggests another way to support the change in habit:

Rather than frame the testing challenge with the default being the old way of not testing:

Write a test when it makes sense.

Change your perspective to the default being to test:

Write a test unless you can explain why you did not.

I like how Steve shifts the focus onto default actions. The actions we take by default arise when our mental habits come into contact with the world. Some of my students prefer to talk about their "instincts", but the principle is the same: When things get hard -- or easy -- what will you do?

We can change our habits. We can develop our instincts. Yes, it is hard to do. However we make the change, we have to change the individual actions we take at each moment of choice.

The way to turn running into a habit is to run. When I have a run planned for a morning but wake up feeling rotten, my default has to be to run. I need to have a really good reason not to run, a reason I am willing to tell my family and running friends without shame. This is another example of using positive peer pressure to help myself act in a desired way.

There are good reasons not to run some days. However, when I am creating a new habit, I have to place the burden of proof on the old habit: Why not?

When I follow this discipline, there is a risk of overusing the technique I am learning. If my default answer is to just keep running, I will run on some mornings when I really should take a break. I may find out during the run, in which case I need to listen to my body immediately and adapt. Or I may find out later, when I see that my times from the workout were substandard or when I am sore or fatigued beyond reason later in the day. Whenever I recognize the problem, I can examine the outcome and try to learn the reason why I should not have run. This will allow me to make a sound exception to my default in the future.

The same risk comes when we try this technique while learning test-driven design or any new programming practice. I may write a test I don't have to write. I may write code that is too simple. I may need it after all. This risk is an integral part of learning. I must learn when not to do something just as much as I need to learn when to do it. The risk of running when I ought not run carries a greater potential cost than writing a test when I need not write, because physical injury may result. The only real cost of writing an unnecessary test or taking too small a step forward in my code is the time lost.

As a runner, the way I minimize the risk of injury or other significant cost I have to listen to my body. As a programmer, I still also have to listen to my code, and keep it clean through refactoring. Done steadily and faithfully, the side effect is a new habit, better instincts.

The key to Steve's suggestion is that changing practice isn't just about habit and instinct, as important as they are. It's also about attitude. There are times when my surface attitude is compliant with a picking up a new practice, but my ingrained attitude gets in the way. My conscious mind may say, "I want to learn how to do TDD", while subconsciously I react as if "I don't need to write a test here". Taking the initiative to change my default action consciously helps me to bridge the gap. I think that's why I find Steve's idea so helpful.


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

June 28, 2010 4:04 PM

Agile Moments: Incremental Design

I love the opening of Research Through Development of Installed Tools, a short section in the conclusion of Richard Stallman's 1979 memo, EMACS: The Extensible, Customizable Display Editor:

The conventional wisdom has it that when a program intended for multiple users is to be written, specifications should be designed in advance. It this is not done, the result will be inferior. The place to try anything new is in a research project which users will not see.

Some people know better than this, but they have been silenced.

If only it were so. The section explains why incremental design was essential to the creation of Emacs:

EMACS could not have been reached by a process of careful design, because such processes arrive only at goals which are visible at the outset, and whose desirability is established on the bottom line at the outset. Neither I nor anyone else visualized an extensible editor until I had made one, nor appreciated its value until he had experienced it. EMACS exists because I felt free to make individually useful small improvements on a path whose end was not in sight.

Agile development teams also like to learn from the act of creating software, allowing goals for the software to emerge as the software grows and allowing the value of features to be assessed in the context of the overall system.

Of course, design still mattered to Stallman and the other developers of Emacs:

While there was no overall goal, each small change had a specific purpose in terms of improving the text editor in general use, and each step had to be individually well designed and reliable.

The resulting design was, according to Hal Ableson (quoted here), good enough to support a new kind of software development community: "Its structure was robust enough that you'd have people all over the world who were loosely collaborating [and] contributing to it. I don't know if that had been done before."

Agile teams use test-driven design, refactoring, and metaphor to keep the quality of their designs on track. Like the Emacs project, agile projects take advantage of real users to keep the usability of their systems on track.

Raymond talks about the value of experimentation in writing new software, relegating upfront design to implementing new versions of existing features. These new implementations can take "advantage of hindsight". I'm often pleasantly reminded just how often an experimental mindset can benefit me as a software developer, even when implementing systems in domains where I have some experience.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

June 25, 2010 12:19 PM

YAGNI: It's Not Just for Agile Programmers Any More

This is the quote of the day from my reading, drawn from a relatively old blog by Giles Bowkett:

YAGNI and "scratch your own itch" don't just keep code clean, elegant, and succinct, they also keep it honest. The worst code you will ever encounter in your career will contain program logic which does something completely different than it claims to, either in its comments or its method, variable, and object names. Programmers spend more time talking about good and evil than priests or preachers do. The reason is simple: bad code is nothing but lies.

I think beginning programmers don't often realize how many different ways that code can lie to us. Moreover, their lack of experience building large programs and living with programs over time usually means that they have no clue at all why this matters, or how important it is.

I am also surprised that so many experienced programmers seem not to grok this yet, especially the role played by doing the simplest thing you can to implement a feature. YAGNI helps us to write more honest code because it helps us to be more honest to ourselves.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

June 12, 2010 11:09 AM

Readings from the Agile Development Course

Last time I mentioned that students in my agile software development course found several of the reading assignments to be valuable. For what it's worth, here is at least a relatively complete list of the readings I assigned in the course of four weeks, in no particular order.

When I still thought we might use a distributed version control system, I asked students to read Hg Init and then a few items on git, including Git for the Lazy, the official git tutorial man page, and Everyday Git. Then, when I decided to show discretion in at least one part of the project and use centralized version control, I asked the class to read several items on Subversion

I'm under no illusion that every student read every page of every reading. This is an ambitious list for agile beginners to tackle in four weeks while also working on a big project. Still, it's clear from discussion that many students read a lot of this material, had questions, and even had comments for me.

As always, I'd love to hear from you any comments you have about this list, or any additions you can suggest for future offerings.


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

June 11, 2010 7:31 PM

Some Feedback on Agile Development Course

Today I finished reviewing materials from my agile software development course so that I could assign final grades. The last thing that students wrote for me was a short evaluation of the course and some of the things we did. Their comments are definitely valuable to me as I think about offering the course again.

What worked best this semester? I was surprised that the class was nearly unanimous in saying pair programming. Their reasons were varied but consistent. By pairing, they faced less down time because one of the two developers usually had an idea for how to proceed. Talking about the roadblock helped them get around it. Several students commented that programming was more fun when working with someone. One student said that he "learned how to explain things better". I imagine that part of this was that, as the team came to build up trust and respect for each other, he wanted to be more patient and helpful when responding to questions. Another part was probably simply practice; pair programming increases communication bandwidth.

The students who did not answer "pair programming" said "learning Ruby". I was hopeful that students would enjoy Ruby and pick it up quickly. But my hope was not grounded in much empirical evidence, so I was a little worried. The language was no worse than a break even proposition for some students, and it was a big win for most. And as a result I had more fun!

I asked students, Who were the best partners you worked with? The best part of these answers is that they were not dominated by a few names, as I thought they might be. There was a pretty good spread of names listed, with only a couple of students mentioned repeatedly. I take this to mean that many students contributed relatively well to the experience of their teammates, which is the sort of horizontal distribution of knowledge that is desired for XP teams. I did note an interesting distinction made by one student between the partner I learned the most from and the partner with whom I felt the most productive.

Which of the assigned readings was most valuable? I include a list of most of the readings I assigned over the course of the four weeks. Of those, two were identified most frequently by students as being valuable: Bill Wake's The Test-First Stoplight, which was assigned early in the semester to give students a sense of the rhythm of test-driven design before diving in as a team, and What is Software Design? by Jack Reeves, which was assigned late in the semester after the team had worked collaboratively for a couple of weeks on a system that had no upfront design and very little documentation. In class discussion, a couple of students disagreed with a few of Reeves's points, but even in those cases the paper engaged and challenged the reader. That's about all I can ask from a paper.

When asked, What did you learn best in the courses?, the answers fell into roughly two groups: TDD and the value of tests and Ruby and OOP. The flip side is that many students also said, "I wish I could have learned more!" Again, that's about all I can ask from any course, that it leave students both happy to have learned something and eager to learn more.

I don't mind that Ruby and object-oriented programming were the prized learning outcomes of a course on agile software development. A couple of times during the course I noted that a good project course is by its nature about everything. We can design courses in neat little bundles, but the work of making anything -- and perhaps especially software -- is a tangled weave of knowledge and discipline and habit that comes together in the act of creating something real. If Ruby and OOP were what some students most needed to learn in May, I'm glad that's what they learned. I will trust that the agile ideas will take root when they are most Needed.

How could I improve the course? This is always a tough question to ask students in an named setting, because no matter how much they might trust me I know that some will be reluctant to say what they really think. Still, I received some answers that will help me design the next iteration of this course. Several times expressed a desire for more time -- to write tests, to pair program, to work on the system outside of class, to practice refactoring, .... It seems that desire for more time is a constant in human experience. (At least they weren't so tired of the course that they all said, "Good riddance!"!) Clearly, there is a trade-off between a four-week semester focused on one course and a fifteen-week semester given over to four or five courses. The loss of absolute number of hours available is a cost of the former. I'll have to think about whether that cost is outweighed by its benefits.

One of the more mature and experienced team members offered an interesting comment: Having an instructor who is a programmer act as client and explain the project requirements to the developers affected a lot of things. He wondered what it would be like to have a non-technical client with the CS instructor acting solely as agile coach. An insightful observation and question!

All in all, this was valuable feedback. The students came through again, as they did throughout the course.


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

June 04, 2010 4:38 PM

The End Comes Quickly

Teaching a 3-credit semester course in one month feels like running on a treadmill that speeds up every morning but never stops. Then the course is over, almost without warning. It reminds me a little bit of how the Christmas season felt to me when I was a child. (I should be honest with myself. That's still how the Christmas season feels to me, because I am still a kid.)

I've blogged about the course only twice since we dove head-long into software development, on TDD and incremental design and on the rare pleasure of pair programming with students. Today, we wrapped up the second of two week-long iterations. Here are the numbers, after we originally estimated 60 units of work for the ideal week:

  • Iteration 1
    • Budgeted work for week: 30 units.
    • Actual work for week: 29.5 units.
    • Story points delivered: 24 units.

  • Iteration 2 (holiday-shortened)
    • Budgeted work: 16 units.
    • Actual work: 18 units.
    • Story points delivered: 11 units.

I was reasonably happy with the amount of software the team was able to deliver, given all the factors at play, among them never having done XP beyond single practices in small exercises, never having worked together before, learning a new programming language, work schedules that hampered the developers' ability to pair program outside our scheduled class time, and working a domain far beyond most of their experiences.

And that doesn't even mention what was perhaps the team's biggest obstacle: me. I had never coached an undergrad team in such an intense, focused setting before. In three weeks, I learned a lot about how to write better stories for a student team and how to coach students better when they ran into problems in the trenches. I hope that I would do a much better job as coach if we were to start working on a second release on Monday. As my good friend Joe Bergin told me in e-mail today, "Just being agile."

We did short retrospectives at the end of both iterations, with the second melting into a retrospective on the project as a whole. In general, the students seemed satisfied with the progress they made in each iteration, even when they still felt uncomfortable with some of the P practices (or remained downright skeptical). Most thought that the foundation practices -- story selection, pair programming, test-first programming, and continuous integration -- worked well in both iterations.

When asked, "What could we improve?", many students gave the same answers, because they recognized we were all still learning. After the first iteration, several team members were still uncomfortable with no Big Design Up Front (BDUF), and a couple thought that we might have avoided needing to devote a day to refactoring if only we had done more design at the beginning. I was skeptical, though, and said so. If we had tried to design the system at the beginning of the project, knowing what we knew then, would we have had as good and as complete a system as we had at the end of the iteration? No way. We learned a lot building our first week's system, and it prepared us for the design we did while refactoring. I could be wrong, but I don't think so.

Most of the developers agreed that the team could be more productive if they were not required to do all of their programming in pairs. With a little guidance from me as the coach, the team decided to loosen the restriction on pairing as follows:

  • If a pair completes a story together, one member of the pair was permitted to work alone to refactor the code they worked on. Honor code: the solo programmer would not create new code, only refactor, and the solo programmer would not make changes to the code that stayed very far from what the pair understood while working together.

  • If a pair is nearly finished with a story, one member of the pair was permitted to work alone to quickly wrap up the story. Honor system: the programmer would work for only 15-30 minutes alone; if it became clear that the work remaining was more involved than a quick wrap-up, the solo programmer stop immediately and resume working with a partner at the next opportunity.

  • A team member may experiment alone, doing a quick spike in an effort to understand some part of the system. Honor system: the solo programmer would commit none of the spike's code; upon returning to the studio, the developer would collaborate on an equal basis within the pair, sharing what was learned via the spike but not ramming it through to the mainline system without agreement and understanding from the partner.

  • At the next daily stand-up, any developer who had worked solo since the previous class session would explain all work done solo to the entire team.

After the second iteration, the team was happy with this adaptation. Only three of the ten developers had worked alone during the iteration, all doing work well within the letter of the new rules and, even more important, well within the spirit of the new rules, too. The rest of the team was happy with the story wrap-up, the refactoring, and the experimentation that had been done. This seemed like a nice win for the group, as it was the one chance to adapt the XP practices to its own needs, and the modification worked well for them. Just being agile!

As part of the course retrospective, I asked the students whether they would have preferred working in a domain they understood better, perhaps allowing them to focus better on the new practices and new programming language. Here are the notes I had made for myself before class, to be shared after they had a chance to answer:

My thoughts on the domain:

I think it was essential that we work in a domain that pushed you out of your comfort zone.

  • It is hard enough to break habits at all, let alone working on problem you already understand well -- or think you do.
  • The benefits of agile approaches come in helping the team to learn and to incorporate that learning into the system.
  • Not knowing the domain forced you to ask lots of questions. That's how real projects work. That's also the best way to work on any system, even ones you think you already understand.
  • There is a realness to reality. Choices matter. When the user is a real person and is passionate about the product, choices matter.

I was so impressed with the answers the students gave. They covered nearly all of my points, sometimes better than I did. One student identified the trade-off between working in familiar and unfamiliar domains. Another student pointed out that not knowing the domain made the team slow down and think, which helped them design better tests and code. Yet another remarked that there probably was no domain that they all knew equally well anyway. The comment that struck me as most insightful was, roughly, "If we worked in a domain we all understand, then we would probably all understand it differently." That captures the problem of requirements analysis as well as anything I've ever read in a software engineering textbook.

It occurred to me while writing this that I should share the list of readings I asked students to study. It's nothing special, papers most people know about about, but it might be a subset of all possible readings that others might find useful. Sharing the list will also make it possible for you to help me make the it better for the next time I offer the course! I'll gather up all of my links and post the list soon.

A few days ago, alumnus Wade Arnold tweeted:

Sad to see May graduates in Computer Science applying to do website design and updates. Seriously where did the art of programming go?

The small and largely disconnected programming problems that we assign students in most courses may engage some students in the joy of programming, but I suspect that these problems do not engage enough students deeply enough. I remain convinced that courses like this one, with a real problem explored more deeply and more broadly, with the student developers more in control of what they do and how, is one of the few things we can do in a traditional university setting to help students grok what software development is all about -- and why it can satisfy in ways that other activities often cannot.

Next up on the teaching front: the compilers course. But first, I turn my thoughts to sustainable pace and look forward to breathing free for a few days.


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

June 01, 2010 9:39 PM

The Rare Pleasure of Pairing

When my student team began the second iteration of our project this morning, one member had no partner. So I jumped in to fill the void for half an hour or so. When the missing student arrived, he joined us and we worked as a trio.

What a treat! Most of the time, I code alone, and far too often the only code I work closely with is code I have written. Working with another programmer was a lot of fun. We talked as we studied and tried our ideas about how the code worked out on one another. Studying someone's code added a second dimension to the fun, because neither of us brought much experience with this part of the system to our pairing session. That meant real study, and real learning.

Our programming session reminded me just how valuable tests can be. We bounced back and forth between the class we needed to extend and its tests. We would study the code, come up with an idea of how it worked, and then inspected the tests to confirm or disconfirm our idea. At one point, we were studying a particularly confusing method. We finally figured out what it was doing and went to the tests to check our understanding. But there was no test to help us... and there should have been. So we wrote a test that embodied what we thought should happen, ran it, and -- voilé -- it passed. That felt good.

The story my partner and I picked out turned out to be effectively solved by the existing code. Rather than taking the easy way out, mark the story as done, and grab another story card, we decided to clean up the code a bit. We were a bit disturbed at having to study that confusing method so long and generally at having to work so hard to understand the class as a whole. So we refactored the class to express the code's intent more clearly. The biggest product of our clean-up was a helper class to structure the parts of a journal entry and name them. This meant taking a horizontal slice of data that was originally sliced vertically. This clarified several of the internal interfaces and even simplified one hairy loop with an if statement that selected on value type into two simpler loops. Ahh.

Is the new code better than the previous version? We think so, but we won't know until the next developers to touch it, whether others our ourselves, bump into it again. I will say that it is at least more explicit. The intention of the code shows up in the names of local variables and formal parameters; it shows up in blocks that send messages to objects of the same kind. It shows up in tests that make finer-grained assertions about the behavior of the system. That feels like an improvement to me and, hopefully, my partners. We'll know more soon enough.

I would love to have more chances like the one I had today.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

May 24, 2010 8:31 PM

Teaching TDD and Incremental Design

Today in the lab while developing code, we encountered another example of stories colliding. We are early in the project, and most parts of the system are still inchoate. So collisions are to be expected.

Today, two pairs were working on stories involving Account objects, which at the start of the day knew only their account number, account name, and current balance. In both stories, the code would have to presume a more knowledgable object, one that knows something about the date of on which the balance is in effect and the various entries that have modified the balance over time.

One team asked, "How can we proceed without knowing the result of the other story?" More importantly, how can either team proceed without knowing how journal transactions will be recorded as entries to the accounts? Implicit in the question, sometimes, is a suggestion disguised as a question: Isn't this an example of where we should do a little up-front design?

In a professional setting, a little up-front design might be the right answer. But with newcomers to XP and TDD, I am trying to have us all think in as pure an XP way as possible. Finding the right point on the continuum between too little up-front design and too much is something better done once the developer has more experience with both ways of working.

This situation is actually a perfect place for us to reinforce the idea behind TDD and why it can help us write better software. Whatever the two pairs do right now, there will likely be some conflicts that need to be merged. Taking that as a given, how can the pairs proceed best? As they write their tests, each should ask itself,

What is the simplest interface we can possibly use to implement this story?

When we write a test, we design a little part of our system's internal interface. Students are used to knowing everything about an already-designed object when they write code to use the object. Programming test-first forces us to think about the interface first, without being privy to implementation. This is good, as it will encourage us to design components that are as loosely coupled as possible. Stories we implement later will impose more specific details on how the object behaves, and we can handle more detailed implementation issues then. This is good, as it encourages us (1) to write simple tests that do not presume any more about the object than is required, and (2) to do the simplest thing that could possibly work to implement the new behavior, because those later stories may well cause our implementation to be extended or changed altogether.

Our story collision is both an obstacle of sorts and an opportunity to let our tests drive us forward in small steps!

This collision also has another lesson in store for us. The whole team has been avoiding a couple of stories about closing journals at the end of the month. Implementing these stories will teach us a lot about what accounts know and look like. By avoiding them, the team has made implementing some of our simplest stories more contingent than they need to be.

Over the weekend, Kent Beck tweeted:

got stuck. wrote a test. unstuck.

A bit he later he followed up:

i get stuck trying to write all the logic at once. feels great to deliberately ignore cases that had me stumped. "that's another test"

This is a skill I hope my students can develop this month. In order for that to happen, I need to watch for opportunities to point them in the right direction. When a pair is at an impasse, unsure of what to do next, I need to suggest that they step back and try to take a smaller step. Write a test for that something smaller, and see where that leads them. The Account saga is a useful example for me to keep in mind.

If nothing else, teaching this course in real time -- in a lab with students testing, designing, and coding all the time -- makes clear something we all know. It is one thing to be able to do something, to react and act in response to the world. It is another thing all together to teach or coach others to do the same thing. I have to have ready at hand questions to ask and suggestions to make as students encounter situations that I handle subconsciously through ingrained experience. Teaching this course is fun on a lot of levels.


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

May 19, 2010 4:39 PM

TDD Exploration on an Agile Student Project

Man, I having fun teaching my agile course. Writing code is fun, and talking design and technique with students in real time is fun. Other than being so intense as to tire me out every day, I think I could get used to this course-in-a-month model.

I had expected that this week would be our first iteration, but it became clear early on that the student team did not understand the domain of our project -- a simple home accounting system I might use -- well enough to begin a development iteration. Progress would have been too slow, and integration too halting, to make the time well-spent.

So, in agile fashion, we adapted. We began our time together yesterday by discussing the problem a bit more at the one-page story level. The team was having difficulty with idea of special journals and different kinds of transactions. We collectively decided to focus on the general journal for recording all transactions, and so adjusted our thinking and our stories.

Then we took inspiration from XP's practice of a spike solution. In XP, a spike is a simple program that helps a team to explore a thorny technical or design problem and learn enough to begin working on live code. As Ward Cunningham relates, a spike is the answer to the question, "What is the simplest thing we can program that will convince us we are on the right track?" For our team, the problem wasn't technical or design-related; it was a purely a matter of insufficient domain understanding.

We paired up, took a simple story, wrote a test, and wrote code. The story was:

Record a check written on May 15 for cash, in the amount of $100.

By writing even one test for this story, the team began to learn new things about the system to be built. For example,

  • A transaction is atomic. You can't add a debit to a journal independent of its balancing credit.

  • Recording a transaction does not update any account. That happens when the journal is closed at the end of the period.

  • There is a difference between the model, the core computation and data of a program, and the view, the way users see or experience the program's behavior. We can and usually should think about these parts of our program as independent.

The first two of these lessons are about the domain. The third is about software design. Both kinds of lesson are essential ones for a young team to to learn, or be reminded of, before building the system.

Some pairs explored this story and its implications for an hour or more. Others tried to forge ahead further, with a second story:

Record receipt of a $200 paycheck, with $100 going to my checking account, $20 to my prepaid medical expense account, and $80 to income tax withholding.

Again, these teams learned something: A transaction may consist of multiple debits or credits. This also means that a transaction must be able to record multiple amounts, unlike in the first story, because several debits may total up to the value of single credit. Finally, if there are multiple debits, the sum of their values must total exactly to the value of the single credit.

Each little bit of learning will help the team to begin to code productively and to be prepared to grow the design of the system.

The development team was not the only party who learned a lot with this spike. By watching the pairs implement a story or two, offering advice and answering questions, I did, too. I play two roles on this project, both as a teacher of sorts. I am the customer for the product and fully intend to use it when the course ends. This makes me a teacher of the domain, both specifically this program and generally Accounting 101. I am also the coach, which finds me helping to guide the XP process as well as teaching students a bit about Ruby, software design, and OO.

By collaborating with the development team as they wrote spike-like code, I learned a lot about how to write better stories. This is true of me as customer, who realized that my original stories lacked the concrete focus the team needed to be able to focus on essential features of the program. It is also true of me as coach, who realized that certain stories would be especially useful in helping the team arrive at a more valuable design more quickly.

It is more than okay for the coach and the customer to learn as much from working with the team as the team members themselves; it is expected. That's one of the great attractions and one of the great assets of agile software development. My students are getting to see that early in their experience with XP.

Tomorrow, I think we will shake of our experimental mindset and begin to write our program. I don't have a lot of experience with a team starting a brand-new system from Code Zero in XP; most of my greenfield development has been on projects where I am the only programmer or the only one writing the initial code base. I am considering trying out advice that @jamesshore tweeted last week:

When starting brand-new product, codebase too small for 8 programmers to work separately. Instead, use projector. 1 driver, 7 nav

This seems like a great way to build an initial code base around a set of commonly-understood objects and interfaces. If I try it out, I will need to avoid one temptation. I will surely want to drive, but I should let a student -- a member of the development team -- control the keyboard!


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

May 17, 2010 5:19 PM

Course Notes from the Treadmill

Teaching a course two hours a day , especially a course that is essentially new in this incarnation, feels like running on ice. I'm enjoying every day, but tomorrow becomes today way too fast!

At the end of last week, I began to feel the effects of compressing a 3-credit course into four weeks. At the end of Week 1, we are a quarter of the way through the course. But one week is not really enough time for all these new ideas to soak into a student's brain or fingertips. TDD, refactoring, pairing, .... Ruby, an IDE, a VCS, ... Our brains take time to adjust. The students are doing remarkably well under the conditions, but some of them are feeling the rush of days, too.

I most noticed the compression in my conflicting desires to do stuff and to talk more about stuff before doing anything big. Most professors tend to err on the side of talking more, but that isn't the best way to learn most disciplines. I decided that we had seen enough background on XP and that students had practiced enough on small exercises such as the spreadsheet TDD challenge and refactoring Fowler's code, Ruby style. It was time to start building software, and learn as we go. So today we played the Planning Game and put ourselves in position to write Line 1 of code tomorrow.

It's been interesting talking to students about XP's practices. Pairing seemed odd to many of them at first, but they seem to have taken to it quickly. They are social beings. Refactoring seems like the Right Thing To Do to many of them, but in practice it is hard. Using a tool like Reek to identify some smells and an IDE like RubyMine to perform some of the refactoring will help, but RubyMine does not yet implement enough different refactorings to really dampen their fear of breaking code.

TDD is causing a couple of programmers fits, because it inverts how they think about coding. When it comes time to write tests for the app they are building -- no longer a small exercise in their minds -- I expect us to struggle as we think about simple design steps. I hope, though, that this practice will get them over the hump to see how writing tests early or first can really affect how we think about our code.

I am still surprised when developers bemoan their inability to deliver working code and then balk so mightily at a practice that could help them in a major way. But, as we all know, old habits die hard. When the mind is ready, change can happen. All we can hope for in a course is to try to be in position for change to occur whenever the mind becomes ready.


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

May 14, 2010 9:15 PM

Greatness, Skill, and Metaprogramming

It's been a long week teaching and doing end-of-year reports for the department, not to mention putting out daily fires. I have a few things to say about the agile development course at the 1/4 mark, but another day.

While writing reports this evening, I listened to several talks and interviews. One was Giles Bowkett's talk on meta-programming at the 2008 Mountain West Ruby Conference. Actually, Bowkett objects to the the idea of meta-programming, as I discussed a few months ago. At one level, I agree with him; it's all just programming. In this talk, he elaborates on this position and does a little just-programming in Ruby to generate code.

The part of this talk that stood out for me this evening was the part of his conclusion in which he discusses Paul Graham's recent work. Bowkett summarizes most of Graham's writing about Lisp, programming, and meta-programming as:

Great programmers can write better programmers than they can hire.

He disagrees with this sentiment in only one word: 'great'. After comically mocking an undue focus on greatness that he attributes to most Harvard grads, he explains that he prefers the more straightforward 'skilled': Skilled programmers can write better programmers than they can hire.

I prefer 'skilled' to 'great' too, because 'great' intimidates too many people. They think other people are or can be great, but that they themselves can be merely ordinary. Maybe so, but ordinary programmers can improve their skills and learn new things. Most ordinary programmers can become skilled programmers, even in the dark art of metaprogramming. They, too, can learn to write better programmers than they can hire, or be.

Of course, this implies that we can help most of the programmers we want to hire be better programmers, by helping them to develop the skills that they need to be good.

If you watch the talk, watch out for a his egregious botching of Lisp syntax in the course of demeaning all those evil parentheses that Lisp foists on us. I would tell him the same thing I tell my students: the parentheses aren't nearly as bad -- or as numerous -- once you learn how to use them properly!


Posted by Eugene Wallingford | Permalink | Categories: Software Development

May 09, 2010 11:53 AM

Technical Debt as Consumption or Investment

A couple of days ago I retweeted a one-liner from @unclebobmartin:

All developers know that bad code slows them down; yet nearly all insist that writing bad code is faster.

This struck me as one of the themes I'd like for my agile software developments students to pick up on this month. It's tempting to write code quick and dirty so that you can feel as if you are ready to move on to the next task. But I as I mentioned here recently, "dirty remains long after quick has been forgotten". The feeling of completion is an illusion, one that we end up paying for later.

A recent student commented that this is the traditional trade-off between "pay now" versus "pay later":

I'd compare it to buying a car today using a loan versus paying outright next year. It's cheaper if you're willing to wait, but can you?

This is an apt analogy, because it allows us to peel off a layer and consider the decision at a deeper level. For example, if I can borrow money at a lower net interest rate than I can earn investing my money elsewhere, then it makes sense for me to borrow. This is a facet of financial borrowing that I think we can learn from in the context of software development. If we can borrow, in the form of technical debt, at a lower net cost than the value of the benefit we can accrue by putting our efforts elsewhere, then it makes sense for us to incur the technical debt.

Seth Godin wrote recently that consumer debt is not your friend. Thinking in this way about software development, we can contrast borrowing for consumption and borrowing for investment. Taking on "consumer" technical debt is a sucker's bet, a losing proposition. This is the sort of debt that agile developers rightly warn us about. Rushing through a story with inadequate testing or with inattention to the shape of the system after we add our code -- just so that we can make a tick on the burndown chart and get more stories done -- this is a habit that eventually buries a team in an avalanche of debt. Pretty soon, we can barely keep up with the minimum monthly payment, and we watch our total debt grow faster than we can add new value to the system. The result is inevitable: bankruptcy.

However, this analogy tells us that there may be a kind of debt that we should be willing to take on. As I described my own thinking above, if I can borrow money at a lower net cost than I can earn investing elsewhere, then it makes sense for me to borrow. Godin writes of borrowing in order to improve your productivity or to buy things that go up in value. In the software development world, this is what I call investment technical debt. If a team makes a thoughtful, conscious decision to let a part of the system fall out of compliance with its usual standards for coding, testing or design because doing so lets them create greater value in another way, then they will be better off in the future for taking on the debt. This is investment, and done well it can pay.

This is the sort of debt that Kent Beck has written about in recent months when he dared to say that it might be okay not to write a test. He has taken a lot of grief from some XP folks, who seem to fear that talking about not following agile practices to the letter will give other developers license to do the wrong thing under the mantle of Beck's advice. I feel for those folks. Investment can be dangerous. People lose money in the stock market all the time, and developers drown in technical debt all the time. It is important for beginners to learn solid fiscal habits, and good development practices, before venturing too far into the world of investing.

But Kent is speaking truth, the same truth my student alluded to when raising the pay-now versus pay-later trade-off. With experience and expertise, developers can begin to take on technical debt for the purpose of investment -- and not only survive, but thrive as a result.

Of course, it is essential that the investor be as honest as possible with herself about being able to repay the debt later. The team must be able to brings its test coverage back up to safe levels for the long term, and it must be able to refactor the system to bring its living design back up to a level that it supports ongoing development. Some teams like to pay down their debt in one or a few large focused episodes. This is akin selling a stock to paying off a note in whole, and I have done this in my own programming more than once.

When I can, though, I prefer to amortize the work of paying off technical debt over a more extended set of development tasks. I still think of this in terms of a relatively quick repayment, maybe a few iterations, because I don't want to the burden of the debt to affect the rhythm of development any longer than it must. (Similarly, I would never take out a 5-year loan to buy a car.) But I prefer the amortized approach because it fits better with how I want to think about my work: always conscious of the state of the system, always taking small steps to make my programs better. As a creature of habit, I like to work within a set of practices that keep me focused on continuous improvement.

That sort of development is not easy to do, or to learn. It's one of the challenges that newcomers to agile software development must overcome. I think back to another part of my student's comment: "It's cheaper if you're willing to wait, but can you?" I think this points out another common choice people face all the time: want versus need. The consumer debt situation in the U.S. is founded in large part on the fact that many consumers confuse wanting something with needing it. I imagine that some of the so-called software crisis has its roots in the same confusion. "We have to write subpar code in order to meet our goal..." -- only to find the team unable to meet its goal in party precisely because it cut corners earlier.

Godin's article closes with an exhortation to resist consumer debt in the face of temptation:

Stuff now is rarely better than stuff later, because stuff now costs you forever if you go into debt to purchase it. ... It takes discipline to forego pleasure now to avoid a lifetime of pain and fees.

Software developers are wise when they take this advice to heart, too. Investment debt is a good idea in certain circumstances, once you have the experience and expertise to take it on wisely, manage it, and pay it off promptly. Consumer debt is always a loser.

My summer agile course is less than 24 hours away. My mind is turning on all cylinders...


Posted by Eugene Wallingford | Permalink | Categories: Software Development

April 30, 2010 10:17 AM

Taking the Pulse of the Agile Community

Thanks to all of you who have written in response to my previous entry with suggestions for my May term course on agile software development. Most everyone recommended what I knew to be true: source control, automated builds, automated testing, and refactoring are the foundation of agile teams. Keep those suggestions coming!

Over the last semester I have been reading the XP mailing list a little more closely in an effort to discern the pulse of the community these days. Every so often an interesting thread pops up. For example, a few months back, the group talked about its general aversion for software done "quick and dirty". One poster quoted Steve McConnell as saying, "The trouble with quick and dirty is that dirty remains long after quick has been forgotten."

This thread stood out starkly against comments from a couple of my colleagues who view agile ideas as a poison, not just a bad idea but a set of temptations that prevent developers from learning The Right Way to make software. They often rail against XP and its ilk as encouraging quick-and-dirty development, producing bad code with no documentation before moving on willy-nilly to the next "story".

That sounded quite funny as I read professionals who use agile practices every day promote unit testing and especially test-driven development as ways to guard against a quick-and-dirty process. Similarly, building refactoring into your weekly, daily, or hourly development cycle is hardly a recipe for reckless development; it is a practice that shows deep care for the code base and for the quality of the software we deliver to our clients.

One of the most active threads on the list over the last few weeks has been a discussion of the "characteristics of a great XP team". This thread has been full of enlightening capsules from people who have been doing XP in the trenches for many years. Some of the discussion offered advice that applies to great teams of any sort, such as a desire to know the truth and adapt to it. Others took a stab at highlighting what XP itself brings to the table. In one especially insightful message, Bill Caputo suggested that, among other attributes, a great P team...

  • can deliver well-tested software at a regular pace indefinitely, because it has "successfully flattened [the] cost-of-change curve".
  • "has mastered the art of adapting [its] process to the needs of [its] environment."
  • "have such a distribution of knowledge ... that any one person could leave [the] team, and [its] velocity would not be negatively impacted any more than any other person leaving."

Steve Gordon decomposed the question that launched the thread into two parts:

  1. What are the characteristics of a great software team?
  2. How does XP achieve -- or not achieve -- these characteristics?

I think Gordon's decomposition serves as a nice way for me and my students to approach our course, and I think Caputo's list is a good start on what we mean when we talk about agile teams.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

April 29, 2010 8:47 PM

Turning My Thoughts to Agile Software Development

April came and went in a flurry. Now begins a busy time of transition. Today was the last session of my programming languages course. This semester taught me a few new things, which I hope to catalog and consider soon.

Ordinarily the next teaching I do after programming languages is the compiler course that follows. I will be teaching that course, in the fall, as we seem to have attracted a healthy enrollment. But my next teaching assignments will be novelty and part-novelty all in one. I am teaching Agile Software Development in our May term, which runs May 10-June 4. This is a novelty for me in several ways. In all my years on the faculty, I have never taught summer school (!), and I have certainly never taught a 3-credit course in only four weeks. I expect the compressed schedule to create an intensity and focus unlike a regular course, but I fear that it will be hard to reflect much as we keep peddling every day for two hours. Full speed ahead!

The course is only part novelty because I have taught Agile Software Development twice before, in regular semesters. I'm also quite in tune with the agile values, principles, and practices. Still, seven years is an eon in the software world, so much has changed since my last offerings in 2003 and prior. Tools such as testing frameworks have evolved, changed outright, or sprung up new. Scrum, lean, and kanban have become major topics of discussion even as the original practices of XP remain the foundation of most agile teams. Languages have faded and surged. There is a lot of new for me in this old course.

The compressed schedule offers opportunities I have not had before when teaching a development course. Class will meet two hours every business day for four weeks. Students will be immersed in this course. Most will be working in the afternoons, but few will be taking a second course. This allows us to engage the material and our projects with an intensity we can't often muster. (I'll also have to be careful to pace the course so that we don't wear ourselves out, which seems a danger. This is a chance for me and the class to practice one of XP's bedrock practices, sustainable pace!)

The class will be small, only a dozen or so, which also offers interesting possibilities for our project. The best way to learn new practices is to use them, and with the class meeting for nearly eleven hours a week we have a chance to dig in and use tools and practice the practices for extended periods, as a group. The chance to pair program and work with a story board has never been so vivid for one of my classes.

I hope that we are able to craft a course and project that help us bypass some of the flaws with typical course projects. Certainly, we will be collocated more frequently and for longer stretches than in my department's usual project course, and we will be together enough to learn to work as a team. There shouldn't be the constant context switching between courses that students face during the academic year. Whether we can manage close interaction with a customer depends a lot on the availability of others and on the project we end up pursuing.

We do face many of the same challenges as my software engineering course last fall. Our curriculum creates a Babel of several programming languages. Students will come to the course with a cavernous range of experience, skills, and maturity. That gap offers a good test of how pair programming collective code ownership, and apprenticeship can help build and share culture and values. The lack of a common tongue is simply a challenge, though, if we hope to deliver software of value in four short weeks.

The next eleven days will find me busy, busy, busy, thinking about my course, organizing readings, and preparing a project and tools.

I am curious to hear what you think:

  • Which ideas, tools, and practices from the agile world ten years ago remain essential today?
  • What changes in the last decade fundamentally changed what we mean by agile development?
  • What readings -- especially accessible primary sources available on the web -- do you recommend?


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

April 22, 2010 8:36 PM

At Some Point, You Gotta Know Stuff

A couple of days ago, someone tweeted a link to Are you one of the 10% of programmers who can write a binary search?, which revisits a passage by Jon Bentley from twenty-five years ago. Bentley observed back than that 90% of professional programmers were unable to produce a correct version of binary search, even with a couple of hours to work. I'm guessing that most people who read Bentley's article put themselves in the elite 10%.

Mike Taylor, the blogger behind The Reinvigorated Programmer, challenged his readers. Write your best version of binary search and report the results: is it correct or not? One of his conditions was that you were not allowed to run tests and fix your code. You had to make it run correctly the first time.

Writing a binary search is a great little exercise, one I solve every time I teach a data structures course and occasionally in courses like CS1, algorithms, and any programming language- or style-specific course. So I picked up the gauntlet.

You can see my solution in a comment on the entry, along with a sheepish admission: I inadvertently cheated, because I didn't read the rules ahead of time! (My students are surely snickering.) I wrote my procedure in five minutes. The first test case I ran pointed out a bug in my stop condition, (>= lower upper). I thought for a minute or so, changed the condition to (= lower (- upper 1)), and the function passed all my tests.

In a sense, I cheated the intent of Bentley's original challenge in another way. One of the errors he found in many professional developers' solution was an overflow when computing the midpoint of the array's range. The solution that popped into my mind immediately, (lower + upper)/2, fails when lower + upper exceeds the size of the variable used to store the intermediate sum. I wrote my solution in Scheme, which handle bignums transparently. My algorithm would fail in any language that doesn't. And to be honest, I did not even consider the overflow issue; having last read Bentley's article many years ago, I had forgotten about that problem altogether! This is yet another good reason to re-read Bentley occasionally -- and to use languages that do heavy lifting for you.

But.

One early commenter on Taylor's article said that the no-tests rule took away some of my best tools and his usual way of working. Even if he could go back to basics, working in an unfamiliar probably made him less comfortable and less likely to produce a good solution. He concluded that, for this reason, a challenge with a no-tests rule is not a good test of whether someone is a good programmer.

As a programmer who prefers an agile style, I felt the same way. Running that first test, chosen to encounter a specific possibility, did exactly what I had designed it to do: expose a flaw in my code. It focused my attention on a problem area and caused me to re-examine not only the stopping condition but also the code that changed the values of lower and upper. After that test, I had better code and more confidence that my code was correct. I ran more tests designed to examine all of the cases I knew of at the time.

As someone who prides himself in his programming-fu, though, I appreciated the challenge of trying to design a perfect piece of code in one go: pass or fail.

This is a conundrum to me. It is similar to a comment that my students often make about the unrealistic conditions of coding on an exam. For most exams, students are away from their keyboards, their IDEs, their testing tools. Those are big losses to them, not only in the coding support they provide but also in the psychological support they provide.

The instructor usually sees things differently. Under such conditions, students are also away from Google and from the buddies who may or may not be writing most of their code in the lab. To the instructor, This nakedness is a gain. "Show me what you can do."

Collaboration, scrapheap programming, and search engines are all wonderful things for software developers and other creators. But at some point, you gotta know stuff. You want to know stuff. Otherwise you are doomed to copy and paste, to having to look up the interface to basic functions, and to being able to solve only those problems Google has cached the answers to. (The size of that set is growing at an alarming rate.)

So, I am of two minds. I agree with the commenter who expressed concern about the challenge rules. (He posted good code, if I recall correctly.) I also think that it's useful to challenge ourselves regularly to solve problems with nothing but our own two hands and the cleverness we have developed through practice. Resourcefulness is an important trait for a programmer to possess, but so are cleverness and meticulousness.

Oh, and this was the favorite among the ones I read:

I fail. ... I bring shame to professional programmers everywhere.

Fear not, fellow traveler. However well we delude ourselves about living in a Garrison Keillor world, we are all in the same boat.


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

April 15, 2010 8:50 PM

Listen To Your Code

On a recent programming languages assignment, I asked students to write a procedure named if->boolean, whose spec was to recognize certain undesirable if expressions and return in their places equivalent but simpler boolean expressions. This procedure could be part of a simple refactoring engine for a Scheme-like language, though I don't know that we discussed it in such terms.

One student's procedure made me smile in a way only a teacher can smile. As expected, his procedure was a cond expression selecting among the undesirable ifs. His procedure began something like this:

    (define if->boolean
      (lambda (exp)
        (cond ((not (if? exp))
                 exp)
              ; Has the form (if condition #t #f)
              ((and (list? exp)
                    (= (length exp) 4)
                    (eq? (car exp) 'if)
                    (exp? (cadr exp))
                    (true-lit? (caddr exp))
                    (false-lit? (cadddr exp)))
                 (if->boolean (cadr exp)))
              ...

The rest of the procedure was more of the same: comments such as

    ; Has the form (if condition #t another)

followed by big and expressions to recognize the noted undesirable if and a call to a helper procedure that constructed the preferred boolean expression. The code was long and tedious, but the comments made its intent clear enough.

Next to his code, I wrote a comment of my own:

Listen to your code. It is saying, "Write syntax procedures!"

How much clearer this code would have been had it read:

    (define if->boolean
      (lambda (exp)
        (cond ((not (if? exp))   exp)
              ((trivial-if? exp) (if->boolean (cadr exp)))
              ...

When I talked about this code in class (presented anonymously in order to guard the student's privacy, in case he desired it), I made it clear that I was not being all that critical of the solution. It was thorough and correct code. Indeed, I praised it for the concise comments that made the intent of the code clearer than it would have been without them.

Still, the code could have been better, and students in the class -- many of whom had written code similar but not always as good as this -- knew it. For several weeks now we have been talking about syntax procedures as a way to define the interface of an ADT and as a way to hide detail that complicates a piece of code.

Syntax Procedure is one pattern in a family of patterns we have learned in order to write structurally-recursive code over an inductive data type. Syntax procedures are, of course, much more broadly applicable than their role in structural recursion, but they are especially useful in helping us to isolate code for manipulating a particular data representation from the code that processes the data values and recurses over their parts. That can be especially useful when students are at the same time still getting used to a language as unusual to them as Scheme.

Michelangelo's Pieta

The note I wrote on the student's printout was one measure of chiding (Really, have you completely forgotten about the syntax procs we've been writing for weeks?) mixed with nine -- or ninety-nine -- measures of stylistic encouragement:

Yes! You have written a good piece of code, but don't stop here. The comment you wrote to help yourself create this code, which you left in so that you would be able to understand the code later, is a sign. Recognize the sign, and use what it says to make your code better.

Most experienced programmers can tell us about the dangers of using comments to communicate a program's intent. When a comment falls out of sync with the code it decorates, woe to future readers trying to understand and modify it. Sometimes, we need a comment to explain a design decision that shapes the code, which the code itself cannot tell us. But most of the time, a comment is just that, a decorator: something meant to spruce up the place when the place doesn't look as good as we know it should. If the lack of syntax procedures in my student's code is a code smell, then his comment is merely deodorant.

Listen to your code. This is one of my favorite pieces of advice to students at all levels, and to professional programmers as well. I even wrote this advice up in a pattern of its own, called Speak the Problem's Language. I knew this pattern from many years writing Smalltalk to build knowledge-based systems in domains from accounting to enginnering. Then I read Peter Norvig's Paradigms of Artificial Intelligence Programming, and his Chapter 2 expressed the wisdom so well that I wanted to make it available as a core coding pattern in all of the pattern languages I was writing at the time. It is still one of my favorites. I hope my student comes to grok it, too.

After class, one of the other students in the class stopped to chat. She is a double major in CS and graphic design, and she wanted to say how odd it was to hear a computer science prof saying, "Listen to your code." Her art professors tell her this sort of thing all time. Let the painting tell you where it wants to go. And, The sculpture is already in the stone; your job is to set it free.

Whatever we want to say about software 'engineering', when we write a program to do something new, our act of creation is not all that different from the painter's, the sculptor's, or the graphic designer's. We shape the code, and it shapes us. Listen.

This was a pretty good way to spend an afternoon talking to students.


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

April 13, 2010 9:03 PM

Unexpected Encounters with Knowledge

In response to a question from Francesco Cirillo, Ward Cunningham says:

Reflecting on your career choices is there anything you would have done differently?

I'm pretty happy with my career, though I never did enough calculus homework if I think how much calculus has influenced how I think in terms of small units of change.

Calculus came up in my programming languages course today, while we were talking about maps, finite functions, and discrete math. Our K-12 system aims students toward calculus, and when they arrive at the university they often end up taking a calculus course if they haven't yet already. Many CS students struggle in calc. They can't help but notice the dearth of applications of calculus in most of their CS courses and naturally ask, "Why are we required to take this class?"

This is a common discussion even among faculty. I can argue both sides of the case, though I admit to believing that understanding the calculus at some level is an essential part of being an educated person, just as understanding the literary and historical context in which one grows and lives is essential. The calculus is one of the crowning achievements of the Enlightenment and helped to usher in the scientific advances that define in large part the world in which we all live today. But Cunningham's reflection encourages us to think about calculus in a different light.

Notice that Cunningham does not talk about direct application of the calculus in any program he wrote. The only program he mentions specifically is WyCash, a portfolio management system. Nor does he talk in an abstract academic way about intellectual achievement and the Age of Reason.

He says instead that the calculus's notion of small units of change has affected the way he thinks. I'm confident that he is thinking here not only of agile software development, with its short iterations and rapid feedback cycle, but also of test-driven development, patterns, and wiki. One can accumulate value in the smallest of the slices. If one accumulates enough of them, then over time the value one amasses can be the area under quite a large curve of action.

This is an indirect application of knowledge. Ward either did enough calculus homework or paid enough attention in class that he was able to understand one of the central ideas underlying the discipline. That understanding probably lay fallow in his mind until he began to see how the idea was recurring in his programming, in his community building, and in his approach to software development. He was then able to think about the implications of the idea in his current work and learn from what we know about the calculus.

I am a fan of Ward's in large part because of his wonderful ability to make such connections. It is hard to anticipate this kind of connection across domains. That's why it's so important to be educated widely and to take seriously ideas from all corners of human accomplishment. Even calc class.


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

March 31, 2010 3:22 PM

"Does Not Play Well With Others"

Today I ran across a recent article by Brian Hayes on his home-baked graphics. Readers compliment him all the time on the great graphics in his articles. How does he do it? they ask. The real answer is that he cares what they look like and puts a lot of time into them. But they want to know what tools he uses. The answer to that question is simple: He writes code!

His graphics code of choice is PostScript. But, while PostScript is a full-featured postfix programming language, it isn't the sort of language that many people want to write general-purpose code in. So Hayes took the next natural step for a programmer and built his own language processor:

... I therefore adopted the modus operandi of writing a program in my language of choice (usually some flavor of Lisp) and having that program write a PostScript program as its output. After doing this on an ad hoc basis a few times, it became clear that I should abstract out all the graphics-generating routines into a separate module. The result was a program I named lips (for Lisp-to-PostScript).

Most of what lips does is trivial syntactic translation, converting the parenthesized prefix notation of Lisp to the bracketless postfix of PostScript. Thus when I write (lineto x y) in Lisp, it comes out x y lineto in PostScript. The lips routines also take care of chores such as opening and closing files and writing the header and trailer lines required of a well-formed PostScript program.

Programmers write code to solve problems. More often than many people, including CS students, realize, programmers write a language processor or even create a little language of their own to make solving the more convenient. We have been covering the idea of syntactic abstractions in my programming languages course for the last few weeks, and Hayes offers us a wonderful example.

Hayes describes his process and programs in some detail, both lips and his homegrown plotting program plot. Still, he acknowledges that the world has changed since the 1980s. Nowadays, we have more and better graphics standards and more and better tools available to the ordinary programmer -- many for free.

All of which raises the question of why I bother to roll my own. I'll never keep up -- or even catch up -- with the efforts of major software companies or the huge community of open-source developers. In my own program, if I want something new -- treemaps? vector fields? the third dimension? -- nobody is going to code it for me. And, conversely, anything useful I might come up with will never benefit anyone but me.

Why, indeed? In my mind, it's enough simply to want to roll my own. But I also live in the real world, where time is a scarce resource and the list of things I want to do grows seemingly unchecked by any natural force. Why then? Hayes answers that question in a way that most every programmer I know will understand:

The trouble is, every time I try working with an external graphics package, I run into a terrible impedance mismatch that gives me a headache. Getting what I want out of other people's code turns out to be more work than writing my own. No doubt this reveals a character flaw: Does not play well with others.

That phrase stood me up in my seat when I read it. Does not play well with others. Yep, that's me.

Still again, Hayes recognizes that something will have to give:

In any case, the time for change is coming. My way of working is woefully out of date and out of fashion.

I don't doubt that Hayes will make a change. Programmers eventually get the itch even with their homebrew code. As technology shifts and the world changes, so do our needs. I suspect, though, that his answer will not be to start using someone else's tools. He is going to end up modifying his existing code, or writing new programs all together. After all, he is a programmer.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

March 24, 2010 7:42 PM

SIGCSE Day 2 -- Al Aho on Teaching Compiler Construction

[A transcript of the SIGCSE 2010 conference: Table of Contents]

Early last year, I wrote a blog entry about using idea's from Al Aho's article, Teaching the Compilers Course, in the most recent offering of my course. When I saw that Aho was speaking at SIGCSE, I knew I had to go. As Rich Pattis told me in the hallway after the talk, when you get a chance to hear certain people speak, you do. Aho is one of those guys. (For me, so is Pattis.)

The talk was originally scheduled for Thursday, but persistent fog over southeast Wisconsin kept several people from arriving at the conference on time, including Aho. So the talk was rescheduled for Fri. I still had to see it, of course, so I skipped the attention-grabbing "If you ___, you might be a computational thinker".

Aho's talk covered much of the same ground as his inroads paper, which gave me the luxury of being able to listen more closely to his stories and elaborations than to the details. The talk did a nice job of putting the compiler course into its historical context and tried to explain why we might well teach a course very different -- yet in many ways similar -- to the course we taught forty, twenty-five, or even ten years ago.

He opened with lists of the top ten programming languages in 1970 and 2010. There was no overlap, which introduced Aho's first big point: the landscape of programming languages has changes in a big way since the beginning of our discipline, and there have been corresponding changes in the landscape of compilers. The dimensions of change are many: the number of languages, the diversity of languages, the number and kinds of applications we write. The growth in number and diversity applies not only to the programming languages we use, which are the source language to a compiler, but also to the target machines and the target languages produced by compilers.

From Aho's perspective, one of the most consequential changes in compiler construction has been the rise of massive compiler collections such as gcc and LLVM. In most environments, writing a compiler is no longer a matter of "writing a program" as much a software engineering exercise: work with a large existing system, and add a new front end or back end.

So, what should we teach? Syntax and semantics are fairly well settled as matter of theory. We can thus devote time to the less mathematical parts of the job, such as the art of writing grammars. Aho noted that in the 2000s, parsing natural languages is mostly a statistical process, not a grammatical one, thanks to massive databases of text and easy search. I wonder if parsing programming languages will ever move in this direction... What would that mean in terms of freer grammar, greater productivity, or confusion?

With the availability of modern tools, Aho advocates an agile "grow a language" approach. Using lex and yacc, students can quickly produce a compiler in approximately 20 lines of code. Due to the nature of syntax-directed translation, which is closely related to structural recursion, we can add new productions to a grammar with relative ease. This enables us to start small, to experiment with different ideas.

The Dragon book circa 2010 adds many new topics to its previous editions. It just keeps getting thicker! It covers much more material, both breadth and depth, than can be covered in the typical course, even with graduate students. This gives instructors lots of leeway in selecting a subset around which to build a course. The second edition already covers too much material for my undergrad course, and without enough of the examples that many students need these day. We end up selecting such a small subset of the material that the price of the book is too high for the number of pages we actually used.

The meat of the talk matched the meat of his paper: the compiler course he teaches these days. Here are a few tidbits.

On the Design of the Course

  • Aho claims that, through all the years, every team has delivered a working system. He attributes this to experience teaching the course and the support they provide students.
  • Each semester, he brings in at least one language designer in as a guest speaker, someone like Stroustrup or Gosling. I's love to do this but don't have quite the pull, connections, or geographical advantage of Aho. I'll have to be creative, as I was the last time I taught agile software development and arranged a phone conference with Ken Auer.
  • Students in the course become experts in one language: the one they create. They become much more knowledgable in several others: the languages they to to write, build, and test their compiler.

On System Development

  • Aho sizes each student project at 3,000-6,000 LOC. He uses Boehm's model to derive a team size of 5, which fits nicely with his belief that 5 is the ideal team size.
  • Every team member must produce at least 500 lines of code on the project. I have never had an explicit rule about this in the past, but experience in my last two courses with team projects tells me that I should.
  • Aho lets teams choose their own technology, so that they can in the way that makes them most comfortable. One serendipitous side effect of this choice is that requires him to stay current with what's going on in the world.
  • He also allows teams to build interpreters for complex languages, rather than full-blown compilers. He feels that the details of assembly language get in the way of other important lessons. (I have not made that leap yet.)

On Language Design

  • One technique he uses to scope the project is to require students to identify an essential core of their language along with a list of extra features that they will implement if time permits. In 15 years, he says, no team has ever delivered an extra feature. That surprises me.
  • In order to get students past the utopian dream of a perfect language, he requires each team to write two or three programs in their language to solve representative problems in the language's domain. This makes me think of test-first design -- but of the language, not the program!
  • Aho believes that students come to appreciate our current languages more after designing a language and grappling with the friction between dreams and reality. I think this lesson generalizes to most forms of design and creation.

I am still thinking about how to allow students to design their own language and still have the time and energy to produce a working system in one semester. Perhaps I could become more involved early in the design process, something Aho and his suite of teaching assistants can do, or even lead the design conversation.

On Project Management

  • "A little bit of process goes a long way" toward successful delivery and robust software. The key is finding the proper balance between too much process, which stifles developers, and too little, which paralyzes them.
  • Aho has experimented with different mechanisms for organizing teams and selecting team leaders. Over time, he has found it best to let teams self-organize. This matches my experience as well, as long as I keep an eye out for obviously bad configurations.
  • Aho devotes one lecture to project management, which I need to do again myself. Covering more content is a siren that scuttles more student learning than it buoys.

~~~~

Aho peppered his talk with several reminiscences. He told a short story about lex and how it was extended with regular expressions from egrep by Eric Schmidt, Google CEO. Schmidt worked for Aho as a summer intern. "He was the best intern I ever had." Another interesting tale recounted one of his doctoral student's effort to build a compiler for a quantum computer. It was interesting, yes, but I need to learn more about quantum computing to really appreciate it!

My favorite story of the day was about awk, one of Unix's great little languages. Aho and his colleagues Weinberger and Kernighan wrote awk for their own simple data manipulation tasks. They figured they'd use it to write throwaway programs of 2-5 lines each. In that context, you can build a certain kind of language and be happy. But as Aho said, "A lot of the world is data processing." One day, a colleague came in to his office, quite perturbed at a bug he had found. This colleague had written a 10,000-line awk program to do computer-aided design. (If you have written any awk, you know just how fantabulous this feat is.) In a context where 10K-line programs are conceivable, you want a very different sort of language!

The awk team fixed the bug, but this time they "did it right". First, they built a regression test suite. (Agile Sighting 1: continuous testing.) Second, they created a new rule. To propose a new language feature for awk, you had to produce regression tests for it first. (Agile Sighting 2: test-first development.) Aho has built this lesson into his compiler course. Students must write their compiler test-first and instrument their build environments to ensure that the tests are run "all of the time". (Agile Sighting 3: continuous integration.)

An added feature of Aho's talk over his paper was three short presentations from members of a student team that produced PixelPower, a language which extends C to work with a particular graphics library. They shared some of the valuable insights from their project experience:

  • They designed their language to have big overlap with C. This way, they had an existing compiler that they understood well and could extend.
  • The team leader decided to focus the team, not try to make everyone happy. This is a huge lesson to learn as soon as you can, one the students in my last compiler course learned perhaps a bit too late. "Getting things done," Aho's students said, "is more important than getting along."
  • The team kept detailed notes of all their discussions and all their decisions. Documentation of process is in many ways much more important than documentation of code, which should be able to speak for itself. My latest team used a wiki for this purpose, which was a good idea they had early in the semester. If anything, they learned that they should have used it more frequently and more extensively.

One final note to close this long report. Aho had this to say about the success of his course:

If you make something a little better each semester, after a while it is pretty good. Through no fault of my own this course is very good now.

I think Aho's course is good precisely because he adopted this attitude about its design and implementation. This attitude serves us well when designing and implementing software, too: Many iterations. Lots of feedback. Collective ownership of the work product.

An hour well spent.


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

March 10, 2010 7:40 PM

Notes on SIGCSE 2010: Table of Contents

The set of entries cataloged here records some of my thoughts and experiences at SIGCSE 2010, in Milwaukee, Wisconsin, March 10-13. I'll update it as I post new essays about the conference.

Primary entries:

Ancillary entries:


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

March 05, 2010 9:21 PM

Mastering Tools and Improving Process

Today, a student told me that he doesn't copy and paste code. If he wants to reuse code verbatim, he requires himself to type it from scratch, character by character. This way, he forces himself to confront the real cost of duplication right away. This may motivate him to refactor as soon as he can, or to reconsider copying the code at all and write something new. In any case, he has paid a price for copying and so has to take it seriously.

The human mind is wonderfully creative! I'm not sure I could make this my practice (I use duplication tactically), but it solves a very real problem and helps to make him an even better programmer. When our tools make it too easy to do something that can harm us -- such as copy and paste with wild abandon, no thought of the future pain it will cause us -- a different process can restore some balance to the world.

The interplay between tools and process came to mind as I read Clive Thompson's Garry Kasparov, cyborg. this afternoon. Last month, I read the same New York Review of Books essay by chess grandmaster Garry Kasparov, The Chess Master and the Computer, that prompted Thompson's essay. When I read Kasparov, I was drawn in by his analysis of what it takes for a human to succeed, as contrasted to what makes computers good at chess:

The moment I became the youngest world chess champion in history at the age of twenty-two in 1985, I began receiving endless questions about the secret of my success and the nature of my talent. ... I soon realized that my answers were disappointing. I didn't eat anything special. I worked hard because my mother had taught me to. My memory was good, but hardly photographic. ...

Garry Kasparov

Kasparov understood that, talent or no talent, success was a function of working and learning:

There is little doubt that different people are blessed with different amounts of cognitive gifts such as long-term memory and the visuospatial skills chess players are said to employ. One of the reasons chess is an "unparalleled laboratory" and a "unique nexus" is that it demands high performance from so many of the brain's functions. Where so many of these investigations fail on a practical level is by not recognizing the importance of the process of learning and playing chess. The ability to work hard for days on end without losing focus is a talent. The ability to keep absorbing new information after many hours of study is a talent. Programming yourself by analyzing your decision-making outcomes and processes can improve results much the way that a smarter chess algorithm will play better than another running on the same computer. We might not be able to change our hardware, but we can definitely upgrade our software.

"Programming yourself" and "upgrading our software" -- what a great way to describe how it is that so many people succeed by working hard to change what they know and what they do.

While I focused on the individual element in Kasparov's story, Thompson focused on the social side: how we can "program" a system larger than a single player? He relates one of Kasparov's stories, about a chess competition in which humans were allowed to use computers to augment their analysis. Several groups of strong grandmasters entered the competition, some using several computers at the same time. Thompson then quotes this passage from Kasparov:

The surprise came at the conclusion of the event. The winner was revealed to be not a grandmaster with a state-of-the-art PC but a pair of amateur American chess players using three computers at the same time. Their skill at manipulating and "coaching" their computers to look very deeply into positions effectively counteracted the superior chess understanding of their grandmaster opponents and the greater computational power of other participants. Weak human + machine + better process was superior to a strong computer alone and, more remarkably, superior to a strong human + machine + inferior process.

Thompson sees this "algorithm" as an insight into how to succeed in a world that consists increasingly of people and machines working together:

[S]erious rewards accrue to those who figure out the best way to use thought-enhancing software. ... The process matters as much as the software itself.

I see these two stories -- Kasparov the individual laboring long and hard to become great, and "weak human + machine + better process" conquering all -- as complements to one another, and related back to my student's decision not to copy and paste code. We succeed by mastering our tools and by caring about our work processes enough to make them better in whatever ways we can.


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

February 27, 2010 9:40 AM

Increasing Duplication to Eliminate Duplication

In a recent entry, I discussed how Kent Beck' design advice "Exploit Symmetries" improves our ability to refactor code. When we take two things that are similar and separate them into parts that are either identical or different, we maximize the repetition in our code. This enables us to factor the repetition in the sharpest way.

Here is a simple example from Scheme. Suppose we are writing a procedure to walk down a vector and count how many of items satisfy a particular condition. Along the way, we might produce code something like this:

  (define count-occurrences-of-test-at
    (lambda (test? von position)
      (if (>= position (vector-length von))
          0
          (if (test? (vector-ref von position))
              (+ 1 (count-occurrences-of-test-at test? von (+ position 1)))
              (count-occurrences-of-test-at test? von (+ position 1))))))

Our procedure duplicates code, but it may not be obvious at first how to factor it away. The problem is that the duplication occurs nested in a larger expression at two different levels: one is a consequent of the if expression, and the other is part of the computation that is the other consequent.

As a first step, we can increase the symmetry in our code by rewriting the else clause as a similar computation:

  (define count-occurrences-of-test-at
    (lambda (test? von position)
      (if (>= position (vector-length von))
          0
          (if (test? (vector-ref von position))
              (+ 1 (count-occurrences-of-test-at test? von (+ position 1)))
              (+ 0 (count-occurrences-of-test-at test? von (+ position 1)))))))

Now we see that the duplicated code is always part of the value of expression, and the if expression itself is about choosing whether to add 1 or 0 to the value of the recursive call. We can use one of the distributive laws of code to factor out the repetition:

  (define count-occurrences-of-test-at
    (lambda (test? von position)
      (if (>= position (vector-length von))
          0
          (+ (if (test? (vector-ref von position)) 1 0)
             (count-occurrences-of-test-at test? von (+ position 1))))))

Voilá! No more duplication. By increasing the duplication in our code, we create a more symmetric relation, and the symmetry enables us to eliminate the duplication entirely. I have never thought of myself as thinking in terms of symmetry when I write code, but I do think in terms of regularity. My mind prefers code with regular form, both on the surface and in the programming structures I use. Often times, my thorniest refactoring problems arise when I let irregular structure sneak into my code. When some duplication or complexity make me uneasy, I find that taking the preparatory step of increasing regularity can help me see a way to simpler code.

Of course, we might approach this problem differently altogether, from a functional point of view, and write a different sort of solution:

  (define count-occurrences-of-test
    (lambda (test? von)
      (apply + (vector-map test? von))))

This eliminates another form of duplication that we find across many procedures that operate on vectors: the common structure of the code simulates a loop over a vector. That is yet another form of regularity that we can exploit, once we begin to recognize it. Then, when we write new code, we can look for ways to express the solution in terms of the functionally mapping pattern, so that we don't have to roll our own loop by hand. When imperative programmers begin to see this form of symmetry, they are on their way to becoming functional programmers. (It is also the kind of symmetry at the heart of MapReduce.)


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

February 19, 2010 4:33 PM

Thoughts on How to Design

Smalltalk Best Practice Patterns is one of my favorite programming books. In it, Kent Beck records some of the design and implementation patterns that he has observed in Smalltalk systems over the years. What makes the book most valuable, though, is that most of its patterns apply beyond Smalltalk, to other object-oriented programming languages and even to non-OO languages. That's because it is really about how we think about and design our programs.

Kent Beck

Kent's latest design endeavor is what he calls the Responsive Design Project, and he reports some of this thinking so far in a recent blog entry. The entry includes a number of short patterns of design. These are not patterns that show up in designs, but patterns of thinking that help give rise to designs. Being hip deep in teaching functional design style to students whose experience is imperative programming, many of Kent's lessons hit home for me.

Inside or Outside. Change the interface or the implementation but not both at the same time.

Winnie the Pooh, a bear of very little brain

This is a classic that bears repeating. It's tempting to start making big changes to even a small piece of code, but whenever we conflate changes to interface and implementation, we risk creating more complexity than our small brains can manage.

Isolate Changes. Before making a change, isolate the area to be changed from the rest of the system so you can change an entire element at a time. For example, before changing a part of a procedure, extract the area to be changed into its own procedure. Make the change, then inline the changed sub-procedure if appropriate.

This one is beyond the ken of most intermediate-level students, so it doesn't show up in my courses often. When we confine a change to a small box, we control the complexity of the change and the range of its effect. This technique can even be used to control software evolution at a higher level.

Exploit Symmetries. Divide similar elements into identical parts and different parts.

Many beginning programmers find it counter-intuitive that the best way to eliminate duplicated code is to increase the level of duplication, maximizing the repetition to the point that it can be factored out in the cleanest and sharpest way. I have come to know this pattern well but sense that its value runs much deeper than the uses to which I've put it thus far.

Then there is the seemingly contradictory pair

Cultivate Confidence. Master your tools. Your feeling of mastery will improve your cognition.

and

Cultivate Humility. Try tools or techniques you aren't comfortable with. Being aware of your limitations will improve your effectiveness.

Of course, the practices themselves aren't contradictory at all, though the notion that one can be confident and humble at the same time might seem to be. But even that holds no contradiction, because it's all about the edge between mastery and learning. I often talk about these patterns in my programming classes, if only hope that a student who is already starting to sense the tension between hubris and humility will know that it's okay to walk the line.

Finally, my nominee for best new pattern name:

Both. Faced with design alternatives without a clear winner, do it every way. Just coding each alternative for an hour is more productive than arguing for days about which is better in theory, and a lot more satisfying.

You may have heard the adage, "Listen to your code", which is often attributed to Kent or to Ward Cunningham. This pattern goes one step beyond. Create the code that can tell you what you need to hear. Time spent talking about what code might do is often much less productive than simply writing the code and finding out directly.

Early in his essay, Kent expresses the lesson that summarizes much of what follows as

Our illusion of control over software design is a dangerous conceit best abandoned.

He says this lesson "disturbs and excites me". I guess I'm not too disturbed by this notion, because feeling out of control when working in a new domain or style or language has become routine for me. I often feel as if I'm stumbling around in the dark while a program grows into just what it needs to be, and then I see it. Then I feel like I'm in control. I knew where I was going all the time.

In my role as a teacher, this pattern holds great danger. It is easy after the fact to walk into a classroom and expound at length about a design or a program as if I understood it all along. Students sometimes think that they should feel in control all the time, too, and when they don't they become discouraged or scared. But the controlled re-telling of the story is a sham; I was no more in control while writing my program than they will be when they write theirs.

What excites me most about this pattern is that it lifts a burden from our backs that we usually didn't know we were carrying. Once we get it, we are able to move on to the real business of writing and learning, confident in the knowledge that we'll feel out of control much of the time.


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

February 15, 2010 10:13 PM

Luck, Embracing Failure, and State of Mind

This morning, Kevlin Henney tweeted:

Being lucky is not generally a matter of luck RT @gregyoung: http://is.gd/8qdIk

That shortened URL points to an article called, Be Lucky: It's an Easy Skill to Learn. The author, psychologist Richard Wiseman, reports some of his findings after a decade studying people who consider themselves lucky or unlucky. Not surprisingly, one's state of mind has as much to do with perception of luck as any events in the observable world. He has identified three common threads that anyone can use to become luckier:

  • Trust your intuition.
  • Use variety and pseudorandom behavior to create opportunities for unexpected benefits.
  • See the positive in each event.

One of the things that struck me about this article was the connection of unlucky people to tension.

... unlucky people are generally much more tense than lucky people, and research has shown that anxiety disrupts people's ability to notice the unexpected.

Tension relates directly to all three of the above bullets. Tense people tend to overthink situations, looking to optimize some metric, and thus quash their gut instincts. They tend to seek routine as a way to minimize distraction and uncertainty, which cause them to miss opportunities. And their tension tends to cause them to see the negative in any event that does not match their desired optimum. Perhaps the key to luck is nothing more than relaxation!

When I think of times I feel unlucky -- and I must sheepishly admit that this happens all too often -- I can see the tension that underlies Wiseman's results. But for me this usually manifests itself as frustration. This thought, in turn, reminded me of a blog entry I wrote a year ago on embracing failure. In it, I considered Rich Pattis observation about how hard computer science must feel to beginners, because it is a discipline learned almost wholly by failure. Not just occasional failure, but a steady stream of failures ranging from syntax errors to misunderstanding complex abstractions. Succeeding in CS requires a certain mindset in which embraces, fights through, or otherwise copes with failure in a constructive way. Some of us embrace it with gusto, seeing failure as a challenge to surmount, not a comment on our value or skills.

I wonder now if there might be a connection between seeing oneself as lucky and embracing failure. Lucky people find positive in the negative events; successful programmers see valuable information in error messages and are empowered to succeed. Lucky people seek out variety and the opportunities it offers; successful programmers try out new techniques, patterns, and languages, not because they seek out failure but because they seek opportunities to learn. Lucky people respect their hunches; successful programmers have the hubris to believe they can see their way to a working program.

If relaxation is the key to removing tension, and removing tension is the key to being lucky, and being lucky is a lot like being a successful programmer, then perhaps the key to succeeding as a programmer is nothing more than relaxation! Yes, that's a stretch, but there is something there.

One last connection. There have been a couple of articles in the popular press recently about an increase in the prevalence of cheating, especially in CS courses. This has led to discussions of cheating in a number of places CS faculty hang out. I imagine there is a close connection between feeling frustrated and tense and feeling like one needs to cheat to succeed. If we can lower the level of tension in our classrooms by lowering the level of frustration, there may be a way for us to stem the growing tide of students cheating. The broader the audience we have in any given classroom, the harder this is to achieve. But we do have tools available to us, including having our students working in domains that give more feedback more visibly, sooner, and more frequently.

One of my favorite comments in all the on-line discussion of cheating in CS is Comment 1 to Mark Guzdial's blog entry, by Steve Tate:

About a decade ago I was chatting with some high school teachers when my university hosted a programming contest for high school kids. One teacher pointed out that her best CS students were those that also played either music or golf -- her theory was that they were used to tasks where you are really bad at first, but you persevere and overcome that. But you have to be able to accept that you'll really stink at it for a good long while.

This struck me as a neat way to make a connection between learning to program and learning music or sports. I had forgotten about the discussion of "meaningful failure" in my own entry... Tate explains the connection succinctly.

Whatever the connections among tension, fear of failure, cheating, and luck, we need to find ways to help students and novice developers learn how to take control of their own destiny -- even if it is only in helping them cultivate their own sense of good luck.


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

February 09, 2010 7:13 PM

Programs as Art

In my previous entry I mentioned colleague and graphic designer Roy Behrens. My first blog articles featuring Behrens mentioned or centered on material from Ballast Quarterly Review, a quarterly commonplace book he began publishing in the mid-1980s. I was excited to learn recently that Behrens is beginning to reproduce material from BALLAST on-line in his new blog, The Poetry of Sight. He has already posted both entries I've seen before and entries new to me. This is a wonderful resource for someone who likes to make connections between art, design, psychology, literature, and just about any other creative discipline.

All this is prelude to my recent reading of the entry Art as Brain Surgery, which recounts a passage from an interview with film theorist Ray Carney that begins the idea behind the entry's title:

The greatest works [of art] do brain surgery on their viewers. They subtly reprogram our nervous systems. They make us notice and feel things we wouldn't otherwise.

I read this passage as a potential challenge to an idea I had explored previously: programming is art. That article looked at the metaphor from poet William Stafford's perspectives on art. Carney looks at art from a different position, one which places a different set of demands on the metaphor. For example,

One of the principal ways [great works of art] do this is through the strangeness of their styles. Style creates special ways of knowing. ... Artistic style induces unconventional states of awareness and sensitivity.

This seems to contradict a connection to programming, a creative discipline in which we seem to prefer -- at least in our code -- convention over individuality, recognizability or novelty, and the obvious over the subtle. When we have to dig into an unfamiliar mass of legacy code, the last thing we want are "unconventional states of awareness and sensitivity". We want to grok the code, and now, so that we can extend and modify it effectively and confidently.

Yet I think we find beauty in programming styles that extend our way of thinking about the world. Many OO and procedural programmers encounter functional programming and see it as beautiful, in part because it does just what Carney says great art does:

It freshens and quickens our responses. It limbers up our perceptions and teaches us new possibilities of feeling and understanding.

The ambitious among us then try to take these new possibilities back to their other programming styles and imbue our code there with the new possibilities. We turn our new perceptions into the conventions and patterns that make our code recognizable and obvious. But this also makes our code subtle in its own, bearing a foreign beauty and sense of understanding in the way it solves the work-a-day problems found in the program's specs. The best software patterns do this: they not only solve a problem but teach us that it can be solved at all, often by bringing an outside influence to our programs.

Perhaps it's just me, but there is something poetic in how I experience the emotional peaks of writing programs. I feel what Carney says:

The greatest works of art are not alternatives to or escapes from life, but enactments of what it feels like to live at the highest pitch of awareness -- at a level of awareness most people seldom reach in their ordinary lives.

The first Lisp interpreter, which taught us that code is data. VisiCalc, which brought program as spreading activation to our desktops, building on AI work in the 1950s and 1960s. Smalltalk. Unix. Quicksort and mergesort, implemented in thousands of programs in thousands of ways, always different but always perceptibly the same. Programmers experience these ideas and programs at the highest pitch of awareness. I walk away from the computer some days hoping that other people get to feel the way I am feeling, alive with fire deep in my bones.

The greatest works are inspired examples of some of the most exciting, demanding routes that can be taken through experience. They bring us back to life.

These days, more than ever, I relish the way even reading a good program can bring me back to life. That's to say nothing of writing one.


Posted by Eugene Wallingford | Permalink | Categories: General, Software Development

January 29, 2010 7:01 PM

Diverse Thinking, Narrative, Journalism, and Software

A friend sent me a link to a New York Times book review, Odysseus Engages in Spin, Heroically, by Michiko Kakutani. My friend and I both enjoy the intersection of different disciplines and people who cross boundaries. The article reviews "The Lost Books of the Odyssey", a recent novel Kakutani calls "a series of jazzy, post-modernist variations on 'The Odyssey'" and "an ingeniously Borgesian novel that's witty, playful, moving and tirelessly inventive". Were the book written by a classicist, we might simply add the book to our to-read list and move on, but it's not. Its author, Zachary Mason is a computer scientist specializing in artificial intelligence.

I'm always glad to see examples of fellow computer scientists with interests and accomplishments in the humanities. Just as humanists bring a fresh perspective when they come to computer science, so do computer scientists bring something different when they work in the humanities. Mason's background in AI could well contribute to how he approaches Odysseus's narrative. Writing programs that make it possible for computers to understand or tell stories causes the programmer to think differently about understanding and telling stories more generally. Perhaps this experience is what enabled Mason to "[pose] new questions to the reader about art and originality and the nature of storytelling".

Writing a program to do any task has the potential to teach us about that task at a deeper level. This is true of mundane tasks, for which we often find our algorithmic description is unintentionally ambiguous. (Over the last couple of weeks, I have experienced this while working with a colleague in California who is writing a program to implement a tie-breaking procedure for our university's basketball conference.) It is all the more true for natural human behaviors like telling stories.

In one of those unusual confluences of ideas, the Times book review came to me the same week that I read Peter Merholz's Why Design Thinking Won't Save You, which is about the value, even necessity, of bringing different kinds of people and thinking to bear on the tough problems we face. Merholz is reacting to a trend in the business world to turn to "design thinking" as an alternative to the spreadsheet-driven analytical thinking that has dominated the world for the last few decades. He argues that "the supposed dichotomy between 'business thinking' and 'design thinking' is foolish", that understanding real problems in the world requires a diversity of perspectives. I agree.

For me, Kakutani's and Merholz's articles intersected in a second way as I applied what they might say about how we build software. Kakutani explicitly connects author Mason's CS background to his consideration of narrative:

["Lost Books" is] a novel that makes us rethink the oral tradition of entertainment that thrived in Homer's day (and which, with its reliance upon familiar formulas, combined with elaboration and improvisation, could be said to resemble software development) ...

When I read Merholz's argument, I was drawn to an analogy with a different kind of writing, journalism:

Two of Adaptive Path's founders, Jesse James Garrett and Jeffrey Veen, were trained in journalism. And much of our company's success has been in utilizing journalistic approaches to gathering information, winnowing it down, finding the core narrative, and telling it concisely. So business can definitely benefit from such "journalism thinking."

So can software development. This passage reminded of a panel I sat on at OOPSLA several years ago, about the engineering metaphor in software development. The moderator of the panel asked folks in the audience to offer alternative metaphors for software, and Ward Cunningham suggested journalism. I don't recall all the connections he made, but they included working on tight deadlines, having work product reviewed by an editor, and highly stylized forms of writing. That metaphor struck me as interesting then, and I have since written about the relationship between software development and writing, for example here. I have also expressed reservations about engineering as a metaphor for building software, such as here and here.

I have long been coming to believe that we can learn a lot about how to build software better by studying intensely almost every other discipline, especially disciplines in which people make things -- even, say, maps! When students and their parents ask me to recommend minors and double majors that go well with computer science, I often mention the usual suspects but always make a pitch for broadening how we think, for studying something new, or studying intensely an area that really interests the students. Good will come from almost any discipline.

These days, I think that making software is like so many things and unlike them all. It's something new, and we are left to find our own way home. That is indeed part of the fun.


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

January 22, 2010 9:23 PM

Calling C. S. Peirce

William Caputo channels the pragmatists:

These days, I believe the key difference between practice, value and principle (something much debated at one time in the XP community and elsewhere) is simply how likely we are to adjust them if things are going wrong for us (i.e., practices change a lot, principles rarely). But none should be immune from our consideration when our actions result in negative outcomes.

To the list of practice, value, and principle, pragmatists like Peirce, James, Dewey, and Meade would add knowledge. When we focus on their instrumental view of knowledge, it easy to forget one of the critical implications of the view: that knowledge is contingent on experience and context. What we call "knowledge" is not unchanging truth about the universe; it is only less likely to change in the face of new experience than other elements of our belief system.

Caputo reminds us to be humble when we work to help others to become better software developers. The old pragmatists would concur, whether in asking us to focus on behavior over belief or to be open to continual adaptation to our environment. This guidance applies to teaching more than just software development.


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

January 08, 2010 4:34 PM

Courage and the Path to Greatness

Last spring, a colleague commented that he didn't think our department spent enough time trying to be great. This made me sad, but it struck me as true. At the time, I wasn't sure how to respond.

All groups have their internal politics. Some political situations are short-lived; others are persistent, endemic. We are no different, and maybe even above average. (Someone has to be!) Political struggles take time and energy. They steal focus.

I think everyone in our group desires to be great. Unfortunately, that's the easy part. For a group to achieve greatness, individuals must work together in a common direction. In our group, it is hard to build consensus on a shared vision. I don't pretend that once we share a vision that greatness will come easily, but it's hard to get anywhere unless everyone is trying to go to the same place -- or at least is using the same criteria for progress.

As for me, in my role as department head, I have not always found -- or created -- the will, the energy, or the tools I need to help us move confidently in the direction of greatness. So, at times, we seem to settle, working locally but not globally.

This train of thought reminds me of a couple of comments James Shore made about stumbling through mediocrity in the context of agile software development:

The emphasis [in the software world] has shifted from "be great" to "be Agile." And that's too bad. As much as I like it, there's really no point in Agile for the sake of Agile.

The point is to be great, or perhaps more accurately, to do great things. Agile approaches are a path, not a destination.

I want to work with people who want to be great. People who aren't satisfied just fitting in. People who are willing to take risks, rock the boat, and change their environment to maximize their productivity, throughput, and value.

One of the things that has surprised me so much about group dynamics since I joined a faculty and perhaps more so since I've been in the position of head is the enormous role that fear plays in how individuals work and interact with one another. It takes courage to take risks, to rock the boat, and to change the environment in which we live and work. It takes courage to be honest. It takes courage to take an action that may make a colleague or supervisor unhappy.

Without courage, especially at key moments, opportunities pass, sometimes before they are even recognized.

I have experienced this in how I interact with others, and occasionally I observe it how colleagues interact with me and others. I never thought that this would be a major obstacle on my path to greatness, or my department's.

(For what it's worth, Shore's second passage also describes the kind of students I like to work with, too. If it is hard for experienced adults to have this sort of gumption, imagine how much tougher an expectation it is to have of young people who are just learning how to step out into the world. Fortunately, as teachers, we have an opportunity to help students grow in this way.)


Posted by Eugene Wallingford | Permalink | Categories: Managing and Leading, Personal, Software Development

January 05, 2010 3:25 PM

In Programming Style, as in Most Things, Moderation

As I prepare for a new semester of teaching programming languages, I've been enjoying getting back into functional programming. Over break, someone somewhere pointed me toward a set of blog entries on why functional programming doesn't work. My first thought as I read the root entry was, "Just use Scheme or Lisp", or for that matter any functional language that supports mutation. But the author explicitly disallows this, because he is talking about the weakness of pure functional programming.

This is common but always seems odd to me. Many of the arguments one sees against FP are against "pure" functional programming: all FP, all the time. No one ever seems to talk in the same way about stateful imperative programming in, say, C. No one seems to place a purity test on stateful programming: "Try writing that without any functions!". Instead, we use state and sequencing and mutation throughout programs, and then selectively use functional style in the parts of the program where it makes sense. Why should FP be any different? We can use functional style throughout, and then selectively use state where it makes sense.

Mixing state and functions is the norm in imperative programming. The same should be true when we discuss functional programming. In the Lisp world, it is. I have occasionally read Lispers say that their big programs are about 90% functional and 10% imperative. That ratio seems a reasonable estimate for the large functional programs I have written, give or take a few percent either way.

Once we get to the point of acknowledging the desirability of mixing styles, the question becomes which proportion will serve us best in a particular environment. In game programming, the domain used as an example in the set of blog entries I read, perhaps statefulness plays a larger role than 10%. My own experience tells me that whenever I can emphasize functional style (or tightly-constrained stateful style, a lá objects), I am usually better off. If I have to choose, I'll take 90:10 functional over 90:10 imperative any day.

If we allow ourselves to mix styles, then solving the author's opening problem -- making two completely unrelated functions interdependent -- becomes straightforward in a functional program: define the functions (or doppelgangers for them) in a closure and 'export' only the functions. To me, this is an improvement over the "pure" stateful approach, as it gives us state and dependent behavior without global variables mucking up the namespace of the program or the mindshare of the programmer.

Maybe part of the problem lies in how proponents of functional programming pitch things. Some are surely overzealous about the virtues of a pure style. But I think as much of the problem lies in how limited people with vast experience and deep understanding of one way to think feel when they move outside their preferred style. Many programmers still struggle with object-oriented programming in much the same way.

Long ago, I learned from Ralph Johnson to encourage people to think in terms of programming style rather than programming paradigm. Style implies choice and freedom of thought, whereas paradigm implies rigidity and single-mindedness. I like to encourage students to develop facility with multiple styles, so that they will feel comfortable moving seamlessly in and out of styles, across borders whenever that suits the program they are writing. It is better for what we build to be defined by what we need, not our limitations.

(That last is a turn of phrase I learned from the book Art and Fear, which I have referenced a couple of times before.)

I do take to heart one piece of advice derived from another article in the the author's set of articles on FP. People who would like to see functional programming adopted more widely could help the cause by providing more guidance to people who want to learn. What happens if we ask a professional programmer to rewrite a video game (the author's specialty) in pure FP, or

... just about any large, complex C++ program for that matter[?] It's doable, but requires techniques that aren't well documented, and it's not like there are many large functional programs that can be used as examples ...

First, both sides of the discussion should step away from the call for pure FP and allow a suitable mix of functional and stateful programming. Meeting in the middle better reflects how real programmers work. It also broadens considerably the set of FP-style programs available as examples, as well as the set of good instructional materials.

But let's also give credence to the author's plea. We should provide better and more examples, and do a better job of documenting the functional programming patterns that professional programmer needs. How to Design Programs is great, but it is written for novices. Maybe Structure and Interpretation of Computer Programs is part of the answer, and I've been excited to see so many people in industry turning to it as a source of professional development. But I still think we can do better helping non-FP software developers make the move toward a functional style from what they do now. What we really need is the functional programming equivalent of the Gang of Four book.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Patterns, Software Development

December 22, 2009 2:57 PM

Agile Themes: Things Students Say

And now even the grading is done. I enjoyed reading my students' answers to exam questions about software engineering, especially agile approaches. Their views were shaped in part by things I said in class, in part by things I asked them to read, and in part by their own experiences writing code. The last of these included a small team project in class, for which two teams adopted many XP practices.

Many people in the software industry have come to think of agile development as implying an incomplete specification. A couple of students inferred this as well, and so came to view one of the weaknesses of agile approaches as a high risk that the team will go in circles or, worse yet, produce an incomplete or otherwise unacceptable system because they did not spend enough time analyzing the problem. Perhaps I can be more careful in how I introduce requirements in the context of agile development.

One exam question asked students to describe a key relationship between refactoring and testing. Several students responded with a variation of "Clean code is easier to test." I am not sure whether this was simply a guess, or this is what they think. It's certainly true that clean code is easier to test, and for teams practicing more traditional software engineering techniques this may be an important reason to refactor. For teams that are writing tests first or even using tests to drive development, this is not quite as important the answer I was hoping for: After you refactor, you need to be able to run the test suite to ensure that you have not broken any features.

Another person wrote an answer that was similar to the one in the preceding paragraph, but I read it as potentially more interesting: "Sometimes you need to refactor in order to test a feature well." Perhaps this answer was meant in the same way as "clean code is easier to test". It could mean something else, though, related to an idea I mentioned last week, design for testability. In XP, refactoring and test-first programming work together to generate the system's design. The tests drive additions to the design, and refactoring ensures that the additions become part of a coherent whole. Sometimes, you need to refactor in order to test well a feature that you want to add in the next iteration. If this is what the student meant, then I think he or she picked up on something subtle that we didn't discuss explicitly in class.

When asked what the hardest part of their project had been and what the team had done in response to the challenge, one student said, "We had difficulty writing code, so we looked for ways to break the story into parts." Hurray! I think this team got then idea.

A question near the end of the exam asked students about Fred Brooks's No Silver Bullet paper. They read this paper early in the semester to get some perspective on software engineering and wrote a short essay about their thoughts on it. After having worked on a team project for ten weeks, I asked them to revisit the paper's themes in light of their experience. One student wrote, "A good programmer is the best solution to engineering software."

A lot of the teams seem to have come to a common understanding that their design and programming skills and those of their teammates were often the biggest impediment to writing the software they envisioned. If they take nothing from this course than the desire and willingness to work hard to become better designers and programmers, then we will have achieved an outcome more important than anything try to measure with a test.

I agree with Brooks and these students. Good programmers are the best solution to engineering software. The trick for us in computer science is how to grow, build, or find great designers and programmers.


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

December 16, 2009 9:51 PM

A Typical Day Thinking Backward

Today I was thinking retrospectively about themes as I wrote the final exam for my software engineering course. It occurred to me that one essential theme of the course needs to be design for testability. We talked about issues such as coupling and cohesion, design heuristics and patterns for making loosely connected, flexible code, and Model-View-Controller as an architectural style. Yet much of the code they wrote was coupled too tightly to test conveniently and thoroughly. I need to help them connect the dots from the sometimes abstract notions of design to both maintenance and testing. This will help me bring some coherence to the design unit of the course.

I am beginning to think that much of the value in this course comes from helping students to see the relationships among the so-called stages of the software life cycle: design and testing, specification and testing, design and maintenance, and so on. Each stage is straightforward enough on its own. We can use our time to consider how they interact in practice, how each helps and hinders the others. Talking about relationships also provides a natural way to discuss feedback in the life cycle and to explore how the agile approaches capitalize on the relationships. (Test-driven development is the ultimate in design for testability, of course. Every bit of code is provoked by a test!)

I realize that these aren't heady revelations. Most of you probably already know this stuff. It's amazing that I can teach a course on writing software for an entire semester, after so many years of writing software myself, and only come to see such a basic idea clearly after having made a first pass. I guess I'm slow. Fortunately, I do seem eventually to learn.

Last night I read a few words that I needed to see. They come from Elizabeth Gilbert, on writing:

Quit your complaining. It's not the world's fault that you wanted to be an artist. It's not the world's job to enjoy the films you make, and it's certainly not the world's obligation to pay for your dreams. Nobody wants to hear it. Steal a camera if you have to, but stop whining and get back to work.

Plug 'programmer' or 'teacher' in for 'artist', and 'laptop' for 'camera', and this advice can help me out on most days. Not because I feel unappreciated, but because I feel pulled in so many directions away from what I really want to do: prepare better courses and -- on far, far too many days -- from writing code. Like Gilbert, I need to repeat those words to myself whenever I start to feel resentful of my other duties. No one cares. I need to find ways to get back to work.

Gilbert closes her essay with more uplifting advice that also feels right:

My suggestion is that you start with the love and then work very hard and try to let go of the results.

If you love to program, or to teach, or to run, you do it. Remember the love that got you into the game, and let it keep you there. The rest will follow.

Oh, and if you haven't seen Gilbert's TED talk, walk back to her home page and watch. It's a good one.


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

December 14, 2009 8:45 PM

Initial Thoughts on Teaching Software Engineering

We have entered finals week, which for me mean grading team projects and writing and grading a final exam. As I think back over the term, a few things stand out.

Analysis. This element of software engineering was a challenge for me. The previous instructor was an expert in gathering requirements and writing specs, but I did not bring that expertise to the course. I need to gather better material for these topics and think about better ways to get help students experience them.

Design and implementation. The middle part of my course disappointed me. These are my favorite parts of making software and the areas about which I know the most, both theoretically and practically. Unfortunately, I never found a coherent approach for introducing the key ideas or giving students deep experiences with them. In the end, my coverage felt too clinical: software architectures, design patterns, refactoring... just ideas. I need to design more convincing exercises to give students a feel for doing these; one big team project isn't enough. Too much of the standard software engineering material here boils down to "how to make UML diagrams". Blech.

Testing. Somewhat to my surprise, I enjoyed this material as much as anything in the course. I think now that I should invert the usual order of the course and teach testing first. This isn't all that crazy, given the relationship between specs and tests, and it would set us up to talk about test-driven design and refactoring in much different ways. The funny thing is that my recently-retired software engineering colleague, who has taught this course for years, said this idea out loud first, with no prompting from me!

More generally, I can think of two ways in which I could improve the course. First, I sublimated my desire to teach an agile-driven course far too much. This being my first time to teach the course, I didn't want to fall victim to my own biases too quickly. The result was a course that felt too artificial at times. With a semester under my belt, I'll be more comfortable next time weaving agile threads throughout the course more naturally.

Second, I really disappointed myself on the tool front. One of my personal big goals for the course was to be sure that students gained valuable experience with build tools, version control, automated testing tools, and a few other genres. Integrating tool usage into a course like this takes either a fair amount of preparation time up front, or a lot more time during the semester. I don't have as much in-semester time as I'd like, and in retrospect I don't think I banked enough up-front time to make up for that. I will do better next time.

One thing I think would make the course work better is to use an open-source software project or two as a running example in class throughout the semester. An existing project would provide a concrete way to introduce both tools and metrics, and a new project would provide a concrete way to talk about most of the abstract concepts and the creative phases of making software.

All this said, I do think that the current version of the course gave students a chance to see what software engineering is and what doing it entails. I hope we did a good enough job to have made their time well-spent.


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

December 07, 2009 9:58 PM

Agile Themes: Working Code and Tests

An undefined problem has an infinite number of solutions.
-- Robert A. Humphrey

It's always seemed to me that one of the best motivations for writing tests first is to know when I'm done. I am prone to wandering in the wilderness and to overthinking what I do. Writing a test helps keep me close to task. When I first heard Kent Beck ask, "How do you know when you are done?", a little light went on for me. I felt something similar when I first saw the above quote on the old "Thinking Again!" blog. A test helps to define my task, circumscribing the problem, taking me from what is usually an incomplete statement in the specification or in a list of requirements to a concrete answer to the question, "Am I done?"

The idea behind test-driven development is that well-written tests can do more. They also evoke a particular design and implementation. This gives me not only an idea of where I am going, but also an idea of how to get there.

That said, an undefined problem may have zero solutions, and executable code can help us avoid this circumstance, too. Adam Bosworth makes this connection in his blog entry on creating healthcare XML standards. He warns against writing standards in the abstract only:

5. Always have real implementations that are actually being used as part of design of any standard. It is hard to know whether something actually works or can be engineered in a practical sense until you actually do it.

Much like analysis and design done independent of any code, a standard written independent of a reference implementation may have big holes in it, not make sense to potential implementors, or even be implementable at all! This ought not be surprising. A standard is a specification for a set of systems that we envision, and our imaginations can outrun our ability to build clear solutions. The best way not to get ahead of ourselves is to build a clear solution as you go along.

The working system we build is a proof of concept for the standard, a concrete implementation that helps us to verify that we are on the right track agile. If those who are intimately familiar with the standard being written cannot implement it, then almost certainly others will struggle more.

This implementation is different than a test in TDD, a mirror image really. But it plays a similar role in helping us to know if you are done. If our reference implementation is unclear or are hard to build, we can find weaknesses in the standard as it is written. If we want to write a good standard, a usable standard, then we are not done.

Bosworth's advice echoes the values that underlie continuous testing in the agile approaches: a preference for working code, a desire to test ideas against reality, and a desire for continuous feedback that we can use to make our product better.

Other advice in Bosworth's article embodies agile values, too, especially a preference for people and simplicity. Consider:

1. Keep the standard as simple and stupid as possible.

2. The data being exchanged should be human readable and easy to understand.

Simplicity and communication, intertwingled.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

December 05, 2009 2:01 PM

Some Things I Have Learned, along with Milton Glaser

I recently came across a link to graphic designer Milton Glaser's 2001 talk Ten Things I Have Learned. Several of his lessons struck close to home for me.

  • After spending time with a person, do you usually feel exhilarated or exhausted? If you always feel tired, then you have been poisoned. Avoid people who do this to you. I would add positive advice in the same vein: Try to surround yourself with people who give you energy, and try to be a person who energizes those around you.

  • Less is not necessarily more. That's a lie we tell ourselves too often when we face cuts. "Do less with more." In the short term, this can be a way to become more efficient. In the long term, it starves us and our organizations. I like Glaser's idea better: Just enough is more.

  • If you think you have achieved enlightenment, "then you have merely arrived at your limitation". I see this too often in academia and in industry. Glaser uses this example of the lesson that doubt is better than certainty, but it also relates to an earlier lesson in the talk: Style is not to be trusted. Styles come and go; integrity and substance remain vital no matter what the fashion is for expressing solutions.

This talk ends with a passage that brought to mind discussion in recent months among agile software developers and consultants about a the idea of certifying agile practitioners:

Everyone interested in licensing our field might note that the reason licensing has been invented is to protect the public not designers or clients. "Do no harm" is an admonition to doctors concerning their relationship to their patients, not to their fellow practitioners or the drug companies.

Much of the discussion in the agile community about certification seems more about protecting the label "agile" from desecration than about protecting our clients. It may well be that some clients are being harmed when unscrupulous practitioners do a lazy or poor job of introducing agile methods, because they are being denied the benefits of a more responsive development process grounded in evidence gathered from continuous feedback. A lot of the concern, though, seems to be with the chilling effect that poorly- executed agile efforts have on the ability of honest and hard-working agile consultants and developers to peddle our services under that banner.

I don't know what the right answer to any of this is, but I like the last sentence of Glaser's talk:

If we were licensed, telling the truth might become more central to what we do.

Whether we are licensed or not, I think the answer will ultimately back to a culture of honesty and building trust in relationships with our clients. So we can all practice Glaser's tenth piece of advice: Tell the truth.


Posted by Eugene Wallingford | Permalink | Categories: General, Software Development

November 30, 2009 10:04 PM

Agile Themes: Organic Planning and the Cost of Change

My previous agile theme, on organic planning, has implications for how we design and implement solutions -- for making decisions that "stick". Derek Sivers recently used an apocryphal story about walkways to express a similar principle:

So when should you make business decisions? When you have the most information, when you're at your smartest: as late as possible.

My first thought was that this principle follows from adaptive planning, but that confuses causal order with temporal order. Sivers's conclusion assumes that we are "at our dumbest at the beginning, and at our smartest at the end". This is the same context in which organic planning applies. It is not always the context in which we work, but when it is, then late binding -- lock-in -- is valuable.

One of the reasons I like to use dynamic programming languages is because they give me late binding in two dimensions: at programming time and at run time. When I'm coding in a domain where I'm not very smart at the outset and become smarter with experience, late binding in programming time seems to make me more productive. Allowing my programs to make decisions as late as possible means that I can imbue my code with the same sense of committing at the right time to an object or function, not sooner.

Implicit in this notion is that our designs and programs will change as we move forward, as we learn more. In the domain of new business ideas, where Sivers works, change and growth are almost unavoidable. Those of us who program in interesting new domains experience a similar pattern of learning and evolution. If change is going to happen, the question becomes, should we load our change into the beginning or end of our development process? Seth Godin knows the answer, whether you work in software, business, or any other creative endeavor:

You must thrash at the beginning, because thrashing at the beginning is cheap.

Some people object to the notion of change as "thrashing", because it sounds unskilled, unprofessional, even undignified. Godin uses the term to indicate the kind of frantic activity that some organizations undertake as they near a deadline and are trying desperately to finish a product that is worthy of delivery. In that context, "thrashing" is a great term. That sort of frantic activity is not wrong in and of itself -- it reflects the group's attempt to incorporate all that it has learned in the course of development. The problem is in the timing: when too many sticky decisions have been made, changing a product to incorporate what we have learned is expensive.

Rather than try to fight against the thrashing, let's instead move it to the beginning of the process, when change is less expensive and when are still figuring out which of our decisions will stick over the long-term. This is how reactive planning, change, and late binding can come together to make us more effective developers.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

November 27, 2009 12:40 PM

Agile Themes: Organic Planning

When I encounter people who are skeptical about agile software development, one of the common concerns I hear is about the lack of planning and design in advance. How can we create software with a coherent design when we don't "really" design? I commented on this concern a while back when mused about reactive planning in AI and software.

Reading last week, I ran across a passage from Lewis Mumford's book "The City in History" that brought to mind a similar trade-off between planning upfront and planning as a system evolves:

Organic planning does not begin with a preconceived goal; it moves from need to need, from opportunity to opportunity, in a series of adaptations that themselves become increasingly coherent and purposeful, so that they generate a complex final design, hardly less unified than a pre-formed geometric pattern.

One thing I like about this passage is its recognition that adaptive planning can produce something that is coherent and purposeful. Indeed, many of us prefer to live in places that have grown organically, with a minimal amount of planning and oversight to keep growth from going off-track. The result can still feel whole in a way that other city designs do not.

I know it is dangerous to extrapolate too casually from other domains into software development, because the analogy may not be a solid one. What this passage offers is something of an existence proof that adaptation through carefully reactive planning can produce solid designs in a domain that people know and understand. This may help us to overcome initial resistance to the idea of agile planning of software long enough that they will give it a try. The real proof comes on software projects -- and many of us have experienced that.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

November 18, 2009 6:45 AM

The Gang-of-Four Book at Fifteen

One of the fun parts of teaching software engineering this semester has been revisiting some basic patterns in the design part of the course, and now as we discuss refactoring in the part of the course that deals with implementation and maintenance. 2009 is the 15th anniversary of the publication of Design Patterns, the book that launched software patterns into the consciousness of mainstream developers. Some folks reminisced about the event at OOPSLA this year, but I wasn't able to make it to Orlando. OOPSLA 2004 had a great 10th-anniversary celebration, which I had the good fortune to attend and write about.

I wasn't present at OOPSLA in 1994, when the book created an unprecedented spectacle in the exhibit hall; that just predates my own debut at OOPSLA. But wish I had been!

InformIT recently ran a series of interviews with OO and patterns luminaries, sharing their thoughts on the book and on how patterns have changed the landscape of software development. The interview with Brian Foote had a passage that I really liked:

InformIT: How has Design Patterns changed your impressions about the way software is built?

The vision of reuse that we had in the object-oriented community in hindsight seems like a God that Failed. Just as the Space Shuttle never lived up to its promised reuse potential, libraries, frameworks, and components, while effective in as far as they went, never became foundations of routine software reuse that many had envisioned and hoped.

Instead, designs themselves, design ideas, patterns became the loci of reuse. We craft our ideas, by hand, into each new artifact we build.

This insight gets to the heart of why patterns matter. Other forms of reuse have their place and use, but they operate at a code level that is ultimately fragile in the face of the different contexts in which our programs operate. So they are, by necessity, limited as vehicles for reuse.

Design ideas are less specific, more malleable. They apply in a million contexts, though never in quite the same way. We mold them to the context of our program. The patterns we see in our designs and tests and implementations give us the abstract raw material out of which to create our programs. We still strive for reuse, but at a different level of thinking and working.

Read the full interview linked above. It is typical Brian Foote: entertaining and full of ideas presented slightly askew from the typical vantage point. That twist helps me to think differently about things that may have otherwise become commonplace. And as so often happens, I had to look a word up in the dictionary before I reached the end. I always seem to learn something from Brian!


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

November 16, 2009 8:32 PM

Towards Software that Improves on Index Cards

Who would have thought that this would turn out to be a major challenge to software developers, software to improve on index cards?

Like a dog gnawing on a bone, I had planned to write more about the topic of software for XP planning. The thread on the XP list just kept on going, and I was sure that I needed to rebut some of the attitude about index cards being the perfect technology for executing XP. I'm not sure why I felt this need. I mostly agree that small cards and fat pens are the best way for us to implement story planning and team communication in XP. Maybe it's an academic's vice to drive any topic into the ground on a technicality.

Fortunately, though, I came to realize that I was punching a strawman. Most of the folks on the list who are talking up the use of low-fi technology don't take a hard stance on reality versus simulation as discussed in my previous post, even when it colors their rhetoric. Most would simply say something like this: "Index cards and felt-tip markers simply work better for us right now than anything else. If someone wants to claim that a software tool can do as well or better, they'll have to show us."

Skepticism and asking for evidence -- many of us all can do better with such an attitude.

I also realized what has been the most interesting result of this discussion thread for me: a chance to see what XP practitioners consider to be the essential features of a planning tool for agile teams. Which characteristics of cards and markers make them so useful? Which characteristics of existing software tools get in the way of doing the job as well as index cards? This includes general-purpose software that we use for XP, say, a spreadsheet, and software built explicitly for P teams (there are many).

As a part of the XP list discussion, Ilja Preuss posted a link to his blog entry on criteria for XP team tools. Here the start of a feature list for XP planning software that I gleaned from that entry and from a few of the articles in the thread:

  • easy to see all the stories at once
  • easy to move the stories around
  • easy to make notations of various sorts on the stories
  • provides visual cues of the size of the system and what stories are most important
  • makes all of the people related to the project comfortable with making changes

The overarching themes in this discussion are high visibility and strong collaboration. In this context, good tools provide more than a one- or even two-way communication medium. In addition to what they communicate, they must communicate in a way that is visible to as many team members as possible at all times. This is the first step toward enabling and encouraging interactivity. One of the most powerful roles that cards play in software development is that of tokens in a cooperative game -- several games, really -- that moves a project forward. Without interactivity, the communication that makes it possible for projects to succeed tends to die off.

Some people are trying to build better tools, and I applaud them. I hope they draw on their own experience and on the experiences we find shared in forums such as the XP list. One tool-in-progress that caught my attention was Taskboardy, which builds on Google Wave. Kent Beck recently tweeted and blogged that he had not yet grokked the need to be satisfied by Wave. Without a killer itch to be scratched, it is hard for a new technology, especially a radically different one, to become indispensable and displace other tools. Maybe the high degree of communication and interactivity demanded by agile software teams is just the sort of need that Wave can satisfy? I don't know, but the best way to find out is for someone to try.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

November 09, 2009 9:54 PM

Reality versus Simulation

A recent discussion on the XP mailing list discussed the relative merits of using physical cards for story planning versus a program, even something as simple as a spreadsheet. Someone had asked, "why not use a program?", and lots of XP aficionados explained why not.

I mostly agree with the explanations, but one undercurrent in the discussion bothered me. It is best captured in this comment:

The software packages are simulations. The board and cards are the real thing.

I was immediately transported twenty years back, to a set of old arguments against artificial intelligence. They went something like this... If we write a program to simulate a rainstorm, we will not get wet; it is just a simulation. By the same token, we can write a program to simulate symbol processing the way we think people do it, but it's not real symbol processing; it is just a simulation. We can write a program to simulate human thought, but it's not real; it's just simulated thought. Just as a simulated rainstorm will not make us wet, simulated thought can't enlighten us. Only human thought is real.

That always raised my hackles. I understand the difference between a physical phenomenon like rain and a simulation of it. But symbol processing and thought are something different. They are physical in our brains, but they manifest themselves in our interactions with the exterior world, including other symbol processors and thinkers. Turing's insight in his seminal paper Computing Machinery and Intelligence was to separate the physical instantiation of intelligent behavior from the behavior itself. The essence of the behavior is its ability to communicate ideas to other agents. If a program can carry on such communication in a way indistinguishable form how humans communicate, then on what grounds are we to say that the simulation is any less real than the real thing?

That seems like a long way to go back for a connection, but when I read the above remark, from someone whose work I greatly respect, it, too, raised my hackles. Why would a software tool that supports an XP practice be "only" a simulation and current practice be the real thing?

The same person prefaced his conclusion above with this, which explains the reasoning behind it:

Every software package out there has to "simulate" some definite subset of these opportunities, and the more of them the package chooses to support the more complex to learn and operate it becomes. Whereas with a physical board and cards, the opportunities to represent useful information are just there, they don't need to be simulated.

The current way of doing things -- index cards and post-it notes on pegboards -- is a medium of expression. It is an old medium, familiar, comfortable, and well understood, but a medium nonetheless. So is a piece of software. Maybe we can't express as much in our program, or maybe it's not as convenient to say what we want to say. This disadvantage is about what we can say or say easily. It's not about reality.

The same person has the right idea elsewhere in his post:

Physical boards and cards afford a much larger world of opportunities for representing information about the work as it is getting done.

Ah... The physical medium fits better into how we work. It gives us the ability to easily represent information as the work is being done. This is about work flow, not reality.

Another poster gets it right, too:

It may seem counterintuitive for those of us who work with technology, but the physical cards and boards are simply more powerful, more expressive, and more useful than electronic storage. Maybe because it's not about storage but communication.

The physical medium is more expressive, which makes it more powerful. More power combined with greater convenience makes the physical medium more useful. This conclusion is about communication. It doesn't make the software tool less real, only less useful or effective.

You will find that communication is often the bottom line when we are talking about software development. The agile approaches emphasize communication and so occasionally reach what seems to be a counterintuitive result for a technical profession.

I agree with the XP posters about the use of physical cards and big, visible boards for displaying them. This physical medium encourages and enhances human communication in a way that most software does not -- at least for now. Perhaps we could create better software tools to support our work? Maybe computer systems will evolve to the point that a live display board will dynamically display our stories, tasks, and status in a way that meshes as nicely with human workflow and teamwork as physical displays do now. Indeed, this is probably possible now, though not as inexpensively or as conveniently as stash of index cards, a cheap box of push pins, and some cork board.

I am open to a new possibility. Framing the issue as one of reality versus simulation seems to imply that it's not possible. I think that perspective limits us more than it helps us.


Posted by Eugene Wallingford | Permalink | Categories: General, Software Development

November 04, 2009 7:33 PM

Wherefore Art Thou Agile?

In recent years, my favorite conference, OOPSLA, has been suffering a strange identity crisis. When the conference began in the mid-1980s, object-oriented programming was a relatively new idea, known to some academics but unheard of by most in industry. By the early 2000s, it had gone mainstream. Most developers understands OOP now, or think they do. Our languages and tools make it seem second nature. We teach it to freshmen in many universities. Who needs a big conference devoted to objects?

As I've written before, say, here, this reflects a fundamental misunderstanding about OOPSLA has always been about. It's a natural misunderstanding, given the name and the marketing hype around it through the 1990s, but a misunderstanding nonetheless. It's hard to unbrand a well-known conference and re-brand it once its existing brand loses its purpose or zip. So OOPSLA struggles a bit. I hear that next year it will become one attraction under the umbrella of a new event, "SPLASH". (More on that later!)

In the last few years, people have begun to notice something similar going on with a younger spinoff from OOPSLA. Agile software development has started to become mainstream. It is over the initial hump of awareness and acceptance. Most everyone knows what 'agile' is, or thinks he does. Its practices have begun to seep into a large number of software houses, whether from Scrum or XP. Our languages and tools now make it possible to work in shorter iterations with continuous feedback and more confidence. We teach it in universities, sometimes even to freshmen. Agile has become old school.

Maybe I'm overstating things a bit, but the buzz has certainly died off. Now we are more likely to hear grumbling. I don't know that many people are asking whether we need conferences devoted to agile approaches yet. But I am starting to read articles that second guess the "movement" and to see a lot of revisionist history. Perhaps this is what happens when the excitement of newness fades into the blandness of same-old, same-old. The excitement passes, and people begin to pay attention more to the chinks in the armor than the strengths that gave the idea birth.

Let's not forget what made agile development and especially XP so galvanizing. William Caputo hasn't forgotten:

But why Agile sells isn't why I liked it. I liked it *because* it put the programmer at the center of the effort of programming (crazy notion that), I didn't need the manifesto to tell me that I had to find ways to make the person paying the money delighted with my efforts, what I needed was a way to tell them that I would gladly do so, if they would just let me.

(The asterisks are his. The bold is mine.)

This is what made XP and the other agile approaches so very important. Focusing on the buyers' needs is easy to do. They pay for software and so have an opportunity to affect strongly the nature of software development. What was missing pre-agile was attention to the developer. I still prefer the term "programmer", with all it implies. It was easy to find ways in which programmers were marginalized, buried beneath processes, documentation, and tools that seemed primarily to serve purposes other than to trust and help programmers to make great software.

The agile movement helped to change that, to shift the perspective from inhuman processes that expected the worst from programmers to practices that celebrate programmers and their love for making software. That some people are now even talking about restating the Agile Manifesto's values toward maximizing shareholder value is a tribute to agile's success at changing the overarching story of the industry.

All this reminds me of an essay by Brian Marick on ease and joy. Agile is about joy at work. We programmers love to make software -- software that improves the lives of its users. Great software. Let us love writing programs, and we can do great things for you.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

November 03, 2009 7:48 PM

Parts of Speech in Programming Languages

I enjoyed Reg Braithwaite's talk Ruby.rewrite(Ruby) (slides available on-line). It gives a nice survey of some metaprogramming hacks related to Ruby's syntactic and semantic structure.

To me, one of the most thought-provoking things Reg says is actually a rather small point in the overall message of the talk. Object-oriented programming is, he summarizes, basically a matter a matter of nouns and verbs, objects and their behaviors. What about other parts of speech? He gives a simple example of an adverb:

blitz.not.blank?

In this expression, not is an adverb that modifies the behavior of blank?. At the syntactic level, we are really telling blitz to behave differently in response to the next message, which happens to be blank?, but from the programmer's semantic level not modifies the predicate blank?. It is an adverb!

Reg notes that some purists might flag this code as a violation of the Law of Demeter, because it sends a message to an object received from another message send. But it doesn't! It just looks that way at the syntax level. We aren't chaining two requests together; we are modifying how one of the requests works, how its result is to be interpreted. While this may look like a violation of the Law of Demeter, it isn't. Being able to talk about adverbs, and thus to distinguish among different kinds of message, helps to make this clear.

It also helps us to program better in at least two ways. First, we are able to use our tools without unnecessary guilt at breaking the letter of a law that doesn't really apply. Second, we are freed to think more creatively about how our programs can say what we mean. I love that Ruby allows me to create constructs such as not and weave them seamlessly into my code. Many of my favorite gems and apps use this feature to create domain-specific languages that look and feel like what they are and look and feel like Ruby -- at the same time. Treetop is an example. I'd love to hear about your favorite examples.

So, our OO programs have nouns and verbs and adverbs. What about other parts of speech? I can think of at least two from Java. One is pronouns. In English, this is a demonstrative pronoun. It is in Java, too. I think that super is also demonstrative pronoun, though it's not a word we use similarly in English. As an object, I consist of this part of me and that (super) part of me.

Another is adjectives. When I teach Java to students, I usually make an analogy from access modifiers -- public, private, and protected -- to adjectives. They modify the variables and methods which they accompany. So do synchronized and volatile.

Once we free ourselves to think this way, though, I think there is something more powerful afoot. We can begin to think about creating and using our own pronouns and adjectives in code. Do we need to say something in which another part of speech helps us to communicate better? If so, how can we make it so? We shouldn't be limited to the keywords defined for us five or fifteen or fifty years ago.

Thinking about adverbs in programming languages reminds me of a wonderful Onward! talk I heard at the OOPSLA 2003 conference. Cristina Lopes talked about naturalistic programming. She suggested that this was a natural step in the evolution from aspect-oriented programming, which had delocalized references within programs in a new way, to code that is concise, effective, and understandable. Naturalistic programming would seek to take advantage of elements in natural language that humans have been using to think about and describe complex systems for thousand of years. I don't remember many of the details of the talk, but I recall discussion of how we could use anaphora (repetition for the sake of emphasis) and temporal references in programs. Now that my mind is tuned to this wavelength, I'll go back to read the paper and see what other connections it might trigger. What other parts of speech might we make a natural part of our programs?

(While writing this essay, I have felt a strong sense of deja vu. Have I written a previous blog entry on this before? If so, I haven't found it yet. I'll keep looking.)


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

November 02, 2009 6:59 PM

It's All Just Programming

One of my colleagues is an old-school C programmer. He can make the machine dance using C. When C++ came along, he tried it for a while, but many of the newly-available features seemed like overkill to him. I think templates fell into that category. Other features disturbed him. I remember him reporting some particularly bad experiences with operator overloading. They made code unreadable! Unmaintainable! You could never be sure what + was doing, let alone operators like () and casts. His verdict: Operator overloading and its ilk are too powerful. They are fine in theory, but real languages should not provide so much freedom.

Some people don't like languages with features that allow them to reconfigure how the language looks and works. I may have been in that group once, long ago, but then I met Lisp and Smalltalk. What wonderful friends they were. They opened themselves completely to me; almost nothing was off limits. In Lisp, most everything was open to inspection, code was data that I could process, and macros let me define my own syntax. In Smalltalk, everything was an object, including the integers and the classes and the methods. Even better, most of Smalltalk was implemented in Smalltalk, right there for me to browse and mimic... and change.

Once I was shown a world bigger than Fortran, PL/I, and Pascal, I came to learn something important, something Giles Bowkett captures in his inimitable, colorful style:

There is no such thing as metaprogramming. It's all just programming.

(Note: "Colorful" is a euphemism for "not safe to read aloud at work, nor to be read by those with tender sensibilities".)

Ruby fits nicely with languages such as Common Lisp, Scheme, and Smalltalk. It doesn't erect too many boundaries around what you can do. The result can be disorienting to someone coming from a more mainstream language such as Java or C, where boundaries between "my program" and "the language" are so much more common. But to Lispers, Schemers, and Smalltalkers, the freedom feels... free. It empowers them to express their ideas in code that is direct, succinct, and powerful.

Actually, when you program in C, you learn the same lesson, only in a different way. It's all just programming. Good C programmers often implement their own little interpreters and their own higher-order procedures as a part of larger programs. To do so, they simply create their own data structures and code to manipulate them. This truth is the raw material out of which Greenspun's Tenth Rule of Programming springs. And that's the point. In languages like C, if you want to use more powerful features, and you will, you have to roll them for yourself. My friends who are "C weenies" -- including the aforementioned colleague -- take great pride in their ability to solve any problem with just a bit more programming, and they love to tell us the stories

Metaprogramming is not magic. It is simply another tool in the prepared programmer's toolbox. It's awfully nice when that tool is also part of the programming language we use. Otherwise, we are limited in what we can say conveniently in our programs by the somewhat arbitrary lines drawn between real and meta.

You know what? Almost everything in programming looks like magic to me. That may seem like an overstatement, but it's not. When I see a program of a few thousand lines or more generate music, play chess, or even do mundane tasks like display text, images, and video in a web browser, I am amazed. When I see one program convert another into the language of a particular machine, I am amazed. When people show me shorter programs that can do these things, I am even more amazed.

The beauty of computer science is that we dig deeper into these programs, learn their ideas, and come to understand how they work. We also learn how to write them ourselves.

It may still feel like magic to me, but in my mind I know better.

Whenever I bump into a new bit of sorcery, a new illusion or a new incantation, I know what I need to do. I need to learn more about how to write programs.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

October 30, 2009 4:31 PM

Writing to Learn, Book-Style

I know all about the idea of "writing to learn". It is one of the most valuable aspects of this blog for me. When I first got into academia, though, I was surprised to find how many books in the software world are written by people who are far from experts on the topic. Over the years, I have met several serial authors who pick a topic in conjunction with their publishers and go. Some of these folks write books that are successful and useful to people. Still the idea has always seemed odd.

In the last few months, I've seen several articles in which authors talk about how they set out to write a book on a topic they didn't know well or even much at all. Last summer, Alex Payne wrote this about writing the tapir book:

I took on the book in part to develop a mastery of Scala, and I've looked forward to learning something new every time I sit down to write, week after week. Though I understand more of the language than I did when I started, I still don't feel that I'm on the level of folks like David Pollak, Jorge Ortiz, Daniel Spiewak, and the rest of the Scala gurus who dove into the language well before Dean or I. Still, it's been an incredible learning experience ...

Then today I ran across Noel Rappin's essay about PragProWriMo:

I'm also completely confident in this statement -- if you are willing to learn new things, and learn them quickly, you don't need to be the lead maintainer and overlord to write a good technical book on a topic. (Though it does help tremendously to have a trusted super-expert as a technical reference.)

Pick something that you are genuinely curious about and that you want to understand really, really well. It's painful to write even a chapter about something that doesn't interest you.

This kind of writing to learn is still not a part of my mentality. I've certainly chosen to teach courses in order to learn -- to have to learn -- something I want to know, or know better. For example, I didn't know any PHP to speak of, so I gladly took on a 5-week course introducing PHP as a scripting language. But I have a respect for books, perhaps even a reverence, that makes the idea of publishing one on a subject I am not expert in unpalatable. I have to much respect for the people who might read it to waste their time.

I'm coming to learn that this probably places an unnecessary limit on myself. Articles like Payne's and Rappin's remind me that I can study something and become expert enough to write a book that is useful to others. Maybe it's time to set out on that path.

Getting people to take this step is one good reason to heed the call of Pragmatic Programmers Writing Month (PragProWriMo), which is patterned after the more generic NaNoWriMo (NaNoWriMo). Writing is like anything else: we can develop a habit that helps us to produce material regularly, which is a first and necessary step to ever producing good material regularly. And if research results on forming habits is right, we probably need a couple of months of daily repetitions to form a habit we can rely on.

So, whether it's a book or blog you have in mind, get to writing.

(Oh, and you really should click through the link in Rappin's essay to Merlin Mann's Making the Clackity Noise for a provocative -- if salty -- essay on why you should write. From there, follow the link to Buffering, where you will find a video of drummer Sonny Payne playing an extended solo for Count Basie's orchestra. It is simply remarkable.)


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

October 29, 2009 4:19 PM

Empirical Data about Software Practices

I was happy to come across Greg Wilson's talk, Bits of Evidence, on empirical data in software engineering. When I started preparing to teach software engineering last summer, I looked for empirical data to support some of the claims that we make about building software. I wasn't all that successful. I figured that either I wasn't looking hard enough, or there wasn't much. The answer probably lies somewhere in the middle.

Someone could do the SE world a great service by gathering, organizing, and providing links to all the good work that has been done. Wilson is one of the people I turn to for pointers to empirical SE results.

I did have fun reading some classic old work in this area. One is McCabe's original article on cyclomatic complexity. This is very cool and has a nice tie to theory, but it simply describes a metric. It does not gather present data from real programs against which the metric has applied, and it doesn't provide any base line for comparison. When he speaks of 10 as a reasonable upper bound for a module's cyclomatic complexity, or of code with cyclomatic complexity in the 3-7 range as "quite well structured", I wonder "Why?" He drew these values from experience looking at production code available to him, but these numbers feel a bit unreliable.

I'm not a stickler who needs statistically significant analysis of carefully collected data, though. I like to learn from experience that is gathered and presented qualitatively. I enjoyed reading about an informal experiment into the complexity of code developed test-first. We need to be careful to take the results with a grain of salt, given the informality of the definitions and methodology used, but the experiment seems to say something useful. I also liked Martin Fowler's reflective analysis of dynamic type checking in production Ruby code from ThoughtWorks. He also wrote an interesting reflection on Ruby at ThoughtWorks that I learned from.

Still, we need more of the sort of empirical evidence that Wilson offers in his talk. As a discipline, we can do a better job of paying attention to the validity of our claims, and of more frequently asking, "Data, please!"


Posted by Eugene Wallingford | Permalink | Categories: Software Development

October 27, 2009 9:47 PM

William Cook on Industry and Academia

I really enjoyed reading the text of William Cook's banquet speech at ECOOP 2009. When I served as tutorials chair for OOPSLA 2006, Cook was program chair, and that gave me a chance to meet him and learn a bit about his background. He has an interesting career story to tell. In this talk, he tells us this story as a way to compare and contrast computer science in academia and in industry. It's well worth a read.

As a doctoral student, I thought my career path might look similar to Cook's. I applied for research positions in industry, with two of the Big Six accounting firms and with an automobile manufacturer, at the same time I applied for academic positions. In the end, after years of leaning toward industry, I decided to accept a faculty position. As a result, my experience with industrial CS research and development is limited to summer positions and to interactions throughout grad school.

Cook's talk needs no summary; you should read it for yourself. Here are a few points that stood out to me as I read:

Venture capitalists talk about pain killers versus vitamins. A vitamin is a product that might make you healthier over the long run, but it's hard to tell. Pain killers are products where the customer screams "give it to me now" and asks what it costs later. Venture capitalists only want to fund pain killers.

This is true not only of venture capitalists, but of lots of people. As a professor, I recognize this in myself and in my students all of the time. Cook points out that most software development tools are vitamins. So are many of the best development practices. We need to learn tools and practices that will make us most productive and powerful in the long run, but without short-term pain we may not generate the resolve to do so.

We read all the standard references on OO for business applications. It didn't make sense to us. We started investigating model-driven development styles. We created modeling languages for data, user interfaces, security and workflow. These four aspects are the core of any enterprise application. We created interpreters to run the languages, and our interpreters did many powerful optimizations by weaving together the different aspects.

To me, this part of the talk exemplifies best how a computer scientist thinks differently than a non-computer scientist, whether experienced in software development or not. Languages are tools we create to help us solve problems, not merely someone else's solutions we pluck off the shelf. Language processors are tools we create to make our languages come to life in solving instances of actual problems.

The way I see it is that industry generally has more problems than they do solutions, but academia often has more solutions than problems.

Cook makes a great case for a bidirectional flow between industry, with its challenging problems in context, and academia, with its solutions built of theory, abstraction, and design. This transfer can be mutually beneficial, but it is complicated by context:

Industrial problems are often messy and tied to specific technical situations or domains. It is not easy to translate these complex problems into something that can be worked on in academia. This translation involves abstraction and selection.

The challenge is greatest when we then take solutions to problems abstracted from real-world details and selected for interestingness more than business value and try to re-inject them into the wild. Too often, these solutions fail to take hold, not because people in industry are "stupid or timid" but because the solution doesn't solve their problem. It solves an ideal problem, not a real one. The translation process from research to development requires a finishing step that people in the research lab often have little interest in doing and that people in the development studio have little time to implement. The result is a disconnect that can sour the relationship unnecessarily.

Finally, the talk is full of pithy lines that I hope to steal and use to good effect sometime soon. Here is my favorite:

Simplicity is not where things start. ... It is where they end.

Computer scientists seek simplicity, whether in academia or in industry. Cook gives us some clues in this talk about how people in these spheres can understand one another better and, perhaps, work better together toward their common goal.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

October 23, 2009 3:11 PM

Universal Ideas of Harmonious Design

I didn't write this comment on the blog entry Wa: The key to clear, harmonious design:

I know that you are talking about visual design, but I am struck by how this approach applies to many other domains.

But I could have.

I started university life intending to become an architect, and my interest in visual design has remained strong through the years. I was delighted when I learned of Christopher Alexander's influence on some in the software world, because it gave me more opportunities to read and think about architectural design -- and to think about how its ideas relate to how we design software. I am quite interested in the notion that there are universal truths about design, and even if not what we can learn from designers in other disciplines.

Garr Reynolds identifies seven principles of the Zen aesthetic of harmony. Like the commenter, my thoughts turned quickly from the visual world to another domain. For me, the domain is software. How well do these principles of harmony apply to software? Several are staples of software design. Others require more thought.

(1) Embrace economy of materials and means
(3) Keep things clean and clutter-free

These are no-brainers. Programmers want to keep their code clean, and most prefer an economical style, even when using a language that requires more overhead than they would like.

(6) Think not only of yourself, but of the other (e.g., the viewer).

When we develop software, we have several kinds of others to consider. The most obvious are our users. We have disciplines, such as human-computer interaction, and development styles, such as user-centered design, focused squarely on the people who will use our programs.

We also need to think of other programmers. These are the people who will read our code. Software usually spends much more time in maintenance than in creation, so readability pays off in a huge way over time. We can help our readers by writing good documentation, an essential complement to our programs. However, the best way to help our readers is to write readable code. In this we are more like Reynolds's presenters. We need to focus on the clarity and beauty of our primary product.

Finally, let's not forget our customers and our clients, the people who pay us to write software. To me, one of the most encouraging contributions of XP was its emphasis on delivering tangible value to our customers every day.

(7) Remain humble and modest.

This is not technical advice. It is human advice. And I think it is underrated in too many contexts.

I have worked with programmers who were not humble enough. Sadly, I have been that programmer, too.

A lack of humility almost always hurts the project and the team. Reynolds is right in saying that true confidence follows from humility and modesty. Without humility, a programmer is prone to drift into arrogance, and arrogance is more dangerous than incompetence.

A programmer needs to balance humility against gumption, the hubris that empowers us to tackle problems which seem insurmountable. I have always found that humility is a great asset when I have the gumption to tackle a big problem. Humility keeps me alert to things I don't understand or might not see otherwise, and it encourages me to take care at each step.

... Now come a couple of principles that cause me to thing harder.

(2) Repeat design elements.

Duplication is a bane to software developers. We long ago recognized that repetition of the same code creates so many problems for writing and modifying software that we have coined maxims such as "Don't repeat yourself" and "Say it one once and only once." We even create acronyms such as DRY to get the idea across in three spare letters.

However, at another level, repetition is unavoidable. A stack is a powerful way to organize and manipulate data, so we want to use one whenever it helps. Rather than copy and paste the code, we create an abstract data type or a class and reuse the component by instantiating it.

Software reuse of this sort is how programmers repeat design elements. Indeed, one of the most basic ideas in all of programming is the procedure, an abstraction of a repeated behavioral element. It is fundamental to all programming, and one of the contributions that computer science made as we moved away from our roots in mathematics.

In the last two decades, programmers have begun to embrace repeatable design units at higher levels. Design patterns recur across contexts, and so now we do our best to document them and share them with others. Architectures and protocols and, yes, even our languages are ways to reify recurring patterns in a way that makes using them as convenient as possible.

(4) Avoid symmetry.

Some programmers may look at this principle and say, "Huh? How can this apply? I'm not even sure what it means in the context of software."

When linguistic structures and data structures repeat, they repeat just as they are, bringing a natural symmetry to the algorithms we use and the code we write. But at the level of design patterns and architectures, things are not so simple. Christopher Alexander, the building architect who is the intellectual forefather of the software patterns community, famously said that a pattern appears a million times, but never exactly the same. The pattern is molded to fit the peculiar forces at play in each system. This seems to me a form of breaking symmetry.

But we can take the idea of avoiding symmetry farther. In the mathematical and scientific communities, there has long been a technical definition of symmetry in groups, as well as a corresponding definition of breaking symmetry in patterns. Only a few people in the software community have taken this formal step with design patterns. Chief among them are Jim Coplien and Liping Zhao. Check out their book chapter, Symmetry Breaking in Software Patterns, if you'd like to learn more.

A few years ago I was able to spend some time looking at this paper and at some of the scientific literature on patterns and symmetry breaking. Unfortunately, I have not been able to return to it since. I don't yet fully understand these ideas, but I think I understand enough to see that there is something important here. This glimmer convinces me that avoiding symmetry is perhaps an important principle for us software designers, one worthy of deeper investigation.

... This leaves us with one more principle from the Presentation Zen article:

(5) Avoid the obvious in favor of the subtle

This is the one principle out of the seven that I think does not apply to writing software. All other things being equal, we should prefer the obvious to the subtle. Doing something that isn't obvious is the single best reason to write a comment in our code. When we must do something unexpected by our readers, we must tell them what we have done and why. Subtlety is an impediment to understanding code.

Perhaps this is a way in which we who work in software differ from creative artists. Subtlety can enhance a work of art, by letting -- even requiring -- the mind to sense, explore, and discover something beyond the surface. As much art as there is in good code, code is at its core a functional document. Requiring maintenance programmers to mull over a procedure and to explore its hidden treasures only slows them down and increases the chances that they will make errors while changing it.

I love subtlety in algorithms and designs, and I think I've learned a lot from reading code that engages me in a way I've not experienced before. But there is something dangerous about code in which subtlety becomes more important than what the program does.

Blaine Buxton recently wrote a nice entry on the idea of devilishly clever code:

But, it got me thinking about clever and production code. In my opinion, clever is never good or wanted in production code. It's great to learn and understand clever code, though. It's a great mental workout to keep you sharp.

Maybe I am missing something subtle here; I've been accused of not seeing nuance before. This may be like the principle of avoiding symmetry, but I haven't reached the glimmer of understanding yet. Certainly, many people speak of Apple's great success with subtle design that engages and appeals to users in a way that other design companies do not. Others, though attribute its success to creating products that are intuitive to use. To me, intuitiveness points more to obviousness and clarity than to subtlety. And besides, Apple's user experience is at the level of design Reynolds is talking about, not at the level of code.

I would love to hear examples, pro and con, of subtlety in code. I'd love to learn something new!


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

October 12, 2009 7:24 PM

X of the Day

Once again, quick hits, for different values of x and different values of day.

Blog Title of the Day

I love the title of this one:

C:\ONGRTLNS.OSX

If you're too old to remember DOS, this may not mean much to you. Ironically, the article is about a vestige of old Mac OS that is disappearing. It's an interesting read, even for non-Mac guys, as an example of software evolution.

Tweet of the Day

The simplest advice is often the best:

i've said it before, @jbogard : never take software advice from a bug tracking system salesman

Duct tape that.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

October 07, 2009 8:11 PM

Refactoring as Rewriting

Reader and occasional writer that I am, Michael Nielsen's Six Rules for Rewriting seemed familiar in an instant. I recognize their results in good writing, and even when I don't practice them successfully in my own writing I know they would often make it better.

Occasional programmer that I am, they immediately had me thinking... How well do they apply to refactoring? Programming is writing, and refactoring is one of our common forms of rewriting... So let's see.

First of all, let's acknowledge up front that a writer's rewriting is not identical to a programmer's refactoring. First of all, the writer does not have automated tests to help her ensure that the rewrite doesn't break anything. It's not clear to me exactly what not breaking anything means for a writer, though I have a vague sense that it is meaningful for most writing.

Also, the term "refactoring" does not refer to any old rewrite of a code base. It has a technical meaning: to modify code without changing its essential functionality. There are rewrites of a code base that are not refactoring. I think that's true of writing in general, though, and I also think that Nielsen is clearly talking about rewrites that do not change the essential content or purpose of a text. His rules are about how to say the same things more effectively. That seems close enough to our technical sense of refactoring to make this exercise worth an effort.

Striking

Every sentence should grab the reader and propel them forward.

Can we say that every line of code should grab the reader and propel her forward?! I certainly prefer to read programs in which every statement or expression tells me something important about what the program is and does. Some programming languages make this harder to do, with boilerplate and often more noise than signal.

Perhaps we could say that every line of code should propel the program forward, not get in the way of its functionality? This says more about the conciseness with which the programmer writes, and fits the spirit of Nielsen's rule nicely.

Every paragraph should contain a striking idea, originally expressed.

Can we say that every function or class should contain a striking idea, originally expressed? Functions and classes that do not usually get in the reader's way. In programming, though, we often write "helpers", auxiliary functions or classes that assist another in expressing an essential, even striking, idea. The best helpers capture an idea of deep value, but it's may be the nature of decomposition that we sometimes create ones that are striking only in the context of the larger system.

The most significant ideas should be distilled into the most potent sentences possible.

Yes! The most significant ideas in our programs should be distilled into the most potent code possible: expressions, statements, functions, classes, whatever the abstractions our language and style provide.

Style

Use the strongest appropriate verb.

Of course. Names matter. Use the strongest, most clearly named primitives and library functions possible. When we create new functions, give them strong, clear names. This rule applies to our nouns, too. Our variables and classes should carry strong names that clearly name their concept. No more "manager" or "process" nouns. They avoid naming the concept. What do those objects do?

This rule also applies more broadly to coding style. It seems to me that Tell, Don't Ask is about strength in our function calls.

Beware of nominalization.

In code, this guideline prescribes a straightforward idea: Don't make a class when a function will do. You Aren't Gonna Need It.

Meta

None of the above rules should be consciously applied while drafting material.

Anyone who writes a lot knows how paralyzing it can be to worry about writing good prose before getting words down onto paper, or into an emacs buffer. Often we don't know what to write until we write it; why try to write that something perfect before we know what it is?

This rule fits nicely with most lightweight approaches to programming. I even encourage novice programmers to write code this way, much to the chagrin of my more engineering-oriented colleagues. Don't be paralyzed by the blank screen. Write freely. Make something work, anything on the path to a solution, and only then worry about making it right and fast. Do the simplest thing that will work. Only after your code works do you rewrite to make it better.

Not all rewriting is refactoring, but all refactoring is rewriting. Write. Pass the test. Refactor.

Many people find that refactoring provides the most valuable use of design patterns, as a target toward which one moves the code. This is perhaps a more important use of patterns than initial design, at which time many of us tend to overdesign our programs. Joshua Kerievsky's Refactoring to Patterns book makes shows programmers how to do this safely and reliably. I wonder if there is any analogue to this book in the writing world, or if there even could be such a book?

I once wrote a post on writing in an agile style, and rewriting played a key role in that idea. Some authors like rewriting more than writing, and I think you can say the same thing of many, many programmers. Refactoring brings a different kind of joy, at getting something right that was before almost right -- which is, of course, another way of saying not yet right.

I recall once talking with a novelist over lunch about tools for writers. Yet even the most humble word processor has done so much to change how authors write and rewrite. One of the comments on Nielsen's entry asks whether new tools for writing have changed the way writers think. We might also ask whether new tools -- the ability to edit and rewrite so much more easily and with so much less= technical effort -- has changed the product created by most writers. If not, could it?

New tools also change how we rewrite code. The refactoring browser has escaped the confines of the Smalltalk image and now graces IDEs for Java, C++, and C## programmers; indeed, refactoring tools exist for so many languages these days. Is that good or bad? Many of my colleagues lament that the ease of rewriting has led to an endemic sloppiness, to a rash of random programming in which students keep making seemingly random changes to their code until something compiles. Back in the good old days, we had to think hard about our code before we carved it into clay tablets... It seems clear to me that making rewriting and refactoring easier is a huge win, even as it changes how we need to teach and practice writing.

In retrospect, a lot of Nielsen's rules generalize to dicta we programmers will accept eagerly. Eliminate boilerplate. Write concise, focused code. Use strong, direct, and clear language. Certainly when we abstract the tasks to a certain level, writing and rewriting really are much the same in text and code.


Posted by Eugene Wallingford | Permalink | Categories: General, Software Development

September 24, 2009 8:07 PM

Always Start With A Test

... AKA Test-Driven X: Teaching

Writing a test before writing code provides a wonderful level of accountability to self and world. The test helps me know what code to write and when we are done. I am often weak and like being able to keep myself honest. Tests also enable me to tell my colleagues and my boss.

These days, I usually think in test-first terms whenever I am creating something. More and more finding myself wondering whether a test-driven approach might work even better. In a recent blog entry, Ron Jeffries asked for analogues of test-driven development outside the software world. My first thought was, what can't be done test-first or even test-driven? Jeffries is, in many ways, better grounded than I am, so rather than talk about accountability, he writes about clarity and concreteness as virtues of TDD. Clarity, concreteness, and accountability seem like good features to build into most processes that create useful artifacts.

I once wrote about student outcomes assessment as a source of accountability and continuous feedback in the university. I quoted Ward Cunningham at the top of that entry, " It's all talk until the tests run.", to suggest to myself a connection to test-first and test-driven development.

Tests are often used to measure student outcomes from courses that we teach at all levels of education. Many people worry about placing too much emphasis on a specific test as a way to evaluate student learning. Among other things, they worry about "teaching to the test". The implication is that we will focus all of our instruction and learning efforts on that test and miss out on genuine learning. Done poorly, teaching to the test limits learning in the way people worry it will. But we can make a similar mistake when using tests to drive our programming, by never generalizing our code beyond a specific set of input values. We don't want to do that in TDD, and we don't want to do that when teaching. The point of the test is to hold us accountable: Can our students actually do what we claim to teach them?

Before the student learning outcomes craze, the common syllabus was the closest thing most departments had to a set of tests for a course. The department could enumerate a set of topics and maybe even a set of skills expected of the course. Faculty new to the course could learn a lot about what to teach by studying the syllabus. Many departments create common final exams for courses with many students spread across many sections and many instructors. The common final isn't exactly like our software tests, though. An instructor may well have done a great job teaching the course, but students have to invest time and energy to pass the test. Conversely, students may well work hard to make sense of what they are taught in class, but the instructor may have done a poor or incomplete job of covering the assigned topics.

I thought a lot about TDD as I was designing what is for me a new course this semester, Software Engineering. My department does not have common syllabi for courses (yet), so I worked from a big binder of material given to me by the person who has taught the course for the last few years. The material was quite useful, but it stopped short of enumerating the specific outcomes of the course as it has been taught. Besides, I wanted to put my stamp on the course, too... I thought about what the outcomes should be and how I might help students reach them. I didn't get much farther than identifying a set of skills for students to begin learning and a set of tools with which they should be familiar, if not facile.

Greg Wilson has done a very nice job of designing his Software Carpentry course in the open and using user stories and other target outcomes to drive his course design. In modern parlance, my efforts in this regard can be tagged #fail. I'm not too surprised, though. For me, teaching a course the first time is more akin to an architectural spike than a first iteration. I have to scope out the neighborhood before I know how to build.

Ideally, perhaps I should have done the spike prior to this semester, but neither the world nor I are ideal. Doing the course this way doesn't work all that badly for the students, and usually no worse than taking a course that has been designed up front by someone who hasn't benefitted from the feedback of teaching the course. In the latter case, the expected outcomes and tests to know they have been met will be imperfect. I tend to be like other faculty in expecting too much from a course the first few times I teach it. If I design the new course all the way to the bottom, either the course is painful for students in expecting too much too fast, or the it is painful for me as I un-design and re-design huge portions of the course.

Ultimately, writing and running tests come back to accountability. Accountability is in short supply in many circles, university curricula included, and tests help us to have it. We owe it to our users, and we owe it to ourselves.


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

September 22, 2009 5:18 PM

Agile Hippies?

The last two class days in my Software Engineering course, I have introduced students to agile software development. Here is a recent Twitter exchange between me and student in the course:

Student: Agile development is the hippy approach to programming.

Eugene: @student: "Agile development is the hippy approach to programming." Perhaps... If valuing people makes me a hippie, so be it.

Student: @wallingf I leave it up to the individual whether they interpret that as good or bad. Personally, I prefer agile, but am also a free spirit

Eugene: @student It's just rare that anyone would mistake me for a hippie...

Student: @wallingf you do like the phrase "roll my own" a lot

I guess I can never be sure what to expect when I tell a story. I've been talking about agile approaches with colleagues for a decade, and teaching them to students off and on since 2002. No student has ever described agile to me as hippie-style development development.

As I think about it from the newcomer's perspective, though, it makes sense. Consider Change, and keep changing, a recent article by Liz Keogh:

Sometimes people ask me, "When we've gone Agile ... what will it look like?" ...

Things will be changing. You'll be in a better place to respond to change. Your people will have a culture of courage and respect, and will seek continuous improvement, feedback and learning. ...

I have no idea what skills your people will need. The people you have are good people; start with them. ...

There is no end-state with Agile or Lean. You'll be improving, and continue to improve, trying new things out and discarding the ones which don't work. ...

I love Liz Keogh's stuff. Is this article representative of the agile community? I think so, at least of a vibrant part of it. Reading this article as I did right after participating in the above exchange, I can see what the student means.

I do not think there is a necessary connection between hippie culture and a preference for agile development. I am so not a hippie. Ask anyone who knows me. I see agile ideas from a perspective of pragmatism. Change happens. Responding to it, if possible, is better than trying to ignore it while it happens before my eyes.

Then again, a lot of my friends in the agile community probably were hippies, or could have been. The Lisp and Smalltalk worlds have long been sources of agile practice, and I am willing to speculate that the counterculture has long been over-represented there. Certainly, those worlds are countercultural amid the laced up corporate world of Cobol, PL/I, and Java.

I decided to google "agile hippie" to see who else has talked about this connection. The top hit talks about common code ownership as "hippie socialism" and highlights the need for a strong team leader to make P work. Hmm. Then the second hit is an essay by Lisp guru and countercultural thinker Richard Gabriel. It refers to agile methodologies as rising from the world of paid consultants and open-source software as the hippie thing.

One of Gabriel's points in this essay echoes something I told my students today: the difference between traditional and agile approaches to software is a matter of degree and style, not a difference in kind. I told my students that nearly all software development these days is iterative development, more or less. The agile community simply prefers and encourages an even tighter spiral through the stages of development. Feedback is good.

Folks may see a hippie connection in agile's emphasis on conversation, working together, and close teamwork. One thing I like about the Gabriel essay is its mention of transparency -- being more open about the process to the rest of the world, especially the client. I need to bring this element out explicitly in my presentation, too,

Maybe even the most straight-laced of agile developers have a touch of hippie radical inside them.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

September 19, 2009 9:09 PM

Quick Hits with an Undercurrent of Change

Yesterday evening, in between volleyball games, I had a chance to do some reading. I marked several one-liners to blog on. I planned a disconnected list of short notes, but after I started writing I realized that they revolve around a common theme: change.

Over the last few months, Kent Beck has been blogging about his experiences creating a new product and trying to promote a new way to think about his design. In his most recent piece, Turning Skills into Money, he talks about how difficult it can be to create change in software service companies, because the economic model under which they operates actually encourages them to have a large cohort of relatively inexperienced and undertrained workers.

The best line on that page, though, is a much-tweeted line from a comment by Niklas Bjørnerstedt:

A good team can learn a new domain much faster than a bad one can learn good practices.

I can't help thinking about the change we would like to create in our students through our software engineering course. Skills and good practices matter. We cannot overemphasize the importance of proficiency, driven by curiosity and a desire to get better.

Then I ran across Jason Fried's The Next Generation Bends Over, a salty and angry lament about the sale of Mint to Intuit. My favorite line, with one symbolic editorial substitution:

Is that the best the next generation can do? Become part of the old generation? How about kicking the $%^& out of the old guys? What ever happened to that?

I experimented with Mint and liked it, though I never convinced myself to go all the way it. I have tried Quicken, too. It seemed at the same time too little and too much for me, so I've been rolling my own. But I love the idea of Mint and hope to see the idea survive. As the industry leader, Intuit has the leverage to accelerate the change in how people manage their finances, compared to the smaller upstart it purchased.

For those of us who use these products and services, the nature of the risk has just changed. The risk with the small guy is that it might fold up before it spreads the change widely enough to take root. The risk with the big power is that it doesn't really get it and wastes an opportunity to create change (and wealth). I suspect that Intuit gets it and so hold out hope.

Still... I love the feistiness that Fried shows. People with big ideas and need not settle. I've been trying to encourage the young people with whom I work, students and recent alumni, to shoot for the moon, whether in business or in grad school.

This story meshed nicely with Paul Graham's Post-Medium Publishing, in which Graham joins in the discussion of what it will be like for creators no longer constrained by the printed page and the firms that have controlled publication in the past. The money line was:

... the really interesting question is not what will happen to existing forms, but what new forms will appear.

Change will happen. It is natural that we all want to think about our esteemed institutions and what the change means for them. But the real excitement lies in what will grow up to replace them. That's where the wealth lies, too. That's true for every discipline that traffics in knowledge and ideas, including our universities.

Finally, Mark Guzdial ruminates on what changes CS education. He concludes:

My first pass analysis suggests that, to make change in CS, invent a language or tool at a well-known institution. Textbooks or curricula rarely make change, and it's really hard to get attention when you're not at a "name" institution.

I think I'll have more to say about this article later, but I certainly know what Mark must be feeling. In addition to his analysis of tools and textbooks and pedagogies, he has his own experience creating a new way to teach computing to non-majors and major alike. He and his team have developed a promising idea, built the infrastructure to support it, and run experiments to show how well it works. Yet... The CS ed world looks much like it always has, as people keep doing what they've always been doing, for as many reasons as you can imagine. And inertia works against even those with the advantages Mark enumerates. Education is a remarkably conservative place, even our universities.


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

September 04, 2009 4:09 PM

Skepticism and Experiment

There's been a long-running thread on the XP discussion list about a variation of pair programming suggested by a list member, on the basis of an experiment run in his shop and documented in a simple research report. One reader is skeptical; he characterized the research as 'only' an experience report and asked for more evidence. Dave Nicolette responded:

Point me to the study that proves...point me to the study that proves...point me to the study that proves...<yawn>

There is no answer that will satisfy the person who demands studies as proof.

Studies aren't proof. Studies are analyses of observed phenomena. The thing a study analyzes has already happened before the study is performed.

... The proof is in the doing.

This is one of those issues where each perspective has value, and even dominates the other under the right conditions.

Skepticism is good. Asking for data before changing how you, your team, or your organization behaves is reasonable. Change is hard enough on people when it succeeds; when it fails, it wastes time and can dispirit people. At times, skepticism is an essential defense mechanism.

Besides, if you are happy with how things work now, why change at all?

The bigger the changes, the more costly the change, the more valuable is skepticism.

In the case of the XP list discussion, though, we see a different set of conditions. The practice being suggested has been tried at one company, so its research report really is "just" an experience report. But that's fine. We can't draw broadly applicable conclusions from an experiment of one anyway, at least not if we want the conclusions to be reliable. This sort of suggestion is really an invitation to experiment: We tried this, it worked for us, and you might want to try it.

If you are dissatisfied with your current practice, then you might try the idea as a way to break out of a suboptimal situation. If you are satisfied enough but have the freedom and inclination to try to improve, then you might try the idea on a lark. When the cost of giving the practice a test drive is small enough, it doesn't take much of a push to do so.

What a practice like this needs is to have a lot of people try it out, under similar conditions and different conditions, to find out if the first trial's success indicates a practice that can be useful generally or was a false positive. That's where the data for a real study comes from!

This sort of practice is one that professional software developers must try out. I could run an experiment with my undergraduates, but they are not (yet) like the people who will use the practice in industry, and the conditions under which they develop are rarely like the conditions in industry. We could gain useful information from such an experiment (especially about how undergrads work and think), but the real proof will come when teams in industry use the practice and we see what happens.

Academics can add value after the fact, by collecting information about the experiments, analyzing the data, and reporting it to the world. That is one of the things that academics do well. I am reminded of Jim Coplien's exhortations a decade and more ago for academic computer scientists to study existing software artifacts, in conjunction with practitioners, to identify useful patterns and document the pattern languages that give rise to good and beautiful programs. While some CS academics continue to do work of this sort -- the area of parallel programming patterns is justifiably hot right now -- I think we in academic CS have missed an opportunity to contribute as much as we might otherwise to software development.

We can't document a practice until it has been tried. We can't document a pattern until it recurs. First we do, then we document.

This reminds me of a blog entry written by Perryn Fowler about a similar relationship between "best practices" and success:

Practices document success; they don't create it.

A tweet before its time...

As I have scanned through this thread on the discussion list, I have found it interesting that some agile people are as skeptical about new agile practices as non-agile folks were (and still are) about agile practices. You would think that we should be practicing XP as it was writ nearly a decade ago. Even agile behavior tends toward calcification if we don't remain aware of why we do what we do.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

August 31, 2009 8:20 PM

Programming Behind the Curtain

Greg Wilson wrote a nice piece recently on the big picture for his Software Carpentry course. His first paragraph captures an idea that is key to the notion of "programming for all" that I and others have been talking about lately:

One of the lessons we learned ... is that most scientists don't actually want to learn how to program--they want solve scientific problems. To many, programming is a tax they have to pay in order to do their research. To the rest, it's something they really would find interesting, but they have a grant deadline coming up and a paper to finish.

Most people don't care about programming. If they do care, they don't like it, or think they don't. They want to do something. Programming has to be a compelling tool, something that makes their lives better as they do the thing they like to do. If it changes how they think about problems and solutions, all the better. When we teach programming to people who are non-CS types, we should present it as such: a compelling tool that makes their lives better. If we teach programming qua programming, we will lose them before we have a chance to make a difference for them.

It turns out that all this is true of CS students, too. Most of them want to do something. And several of the lessons Wilson describes for working with scientists learning to program apply to CS students, such as:

  • When students have never experienced the pain of working with big or long-lived programs that benefit from good abstractions, effective interfaces, and tools such as version control systems, "no amount of handwaving is going to get the idea across".
  • The best way to reach students is to give them programming skills that will pay off for them in the short term. This motivates better than deferred benefit and encourages them to dig in deeper on their own. That's where the best learning happens anyway.
  • Students are often surprised when a course is able to "convey the fundamental ideas needed to make sensible decisions about software without explicitly appearing to do so".

This issue is close to the surface for me as I work on my work on my software engineering course. Undergraduate courses don't usually expose students to the kind of software development projects that are likely to give the right context for learning many of the "big picture" ideas. An in-course project can help, but contemporaneous experience often runs out of sync with the software engineering content of the course. Next semester, they will take a project course in which they can apply what they learn in this course, but little good that does us now!

(Idea for later: Why not teach the project course first and follow with course that teaches techniques that depend on the experience?)

Fortunately, most students trust their professors and give them some leeway when learning skills that are beyond their experience to really grok -- especially when the skills and ideas are a known part of the milieu in which they will work.

Software Engineering this semester offers another complication. There is a wide spread in the level of software and programming experience between the most and least experienced students in the course. What appeals to students at one end of the spectrum often won't appeal students on the other. More fun for the professor...

In closing, I note that many of specific ideas from Wilson's course and Udell's conception of computational thinking apply to a good Software Engineering course for majors. (Several of Wilson's extensions to the body of CT apply less well, in part because they are part of other courses in the CS curriculum and in part because they go beyond the CT that every person probably needs.) I should not be surprised that these basic ideas apply. Wilson is teaching a form of software engineering aimed at a specific audience of developers, and computational thinking is really just a distillation of what all CS students should be learning throughout their undergraduate careers!


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

August 26, 2009 1:19 PM

The Trade-off Between Process and Tools

Mark Guzdial blogged this morning about a bug slipped through into the latest release of JES, the Jython IDE that his group has created to support courses and workshops in media computation. The bug was the result of a simple variable renaming in which n-1 of the uses was changed. (That nth always comes back to haunt us.) Mark uses this bug as an opportunity to discuss some bigger issues involving process, language, and the nature of CS1. He is taking some heat from a couple of pro-Python commenters, but I'm glad he wrote the article. People too rarely share mistakes when they are made, and besides Mark offers some interesting ideas both in his post and in his responses to comments.

Should we use a different kind of language when we program for others than when we program for ourselves? A compiler would have found this simple error at the time JES was built and saved everyone the grief of a new release. But so would running the test suite that the JES team has built. The difference is that developers have a choice of running the test suite or not, whether they use a compiled language or an interpreted one, but they have to compile their program when they use a compiled language.

People make mistakes. I am certainly not in a position to look down on the poor developer who opted not to run the unit tests after making what seemed like a trivial change. I have made similar mistakes before, and I'm sure I'll make another like it soon. And at least one thing is true about teaching university courses: students will find my mistakes!

I like it when a compiler catches errors like this for me, but... Still, I'm uneasy to give up the freedom that a language like Smalltalk, Scheme, or Ruby gives me when I am writing code. Even when the value of Mark's f() rises. What is someone like me to do?

The compiler is a tool that helps me find a certain kind of error. But there are other tools that help me find this and other kinds of error. The unit tests are one. A refactoring browser is another. If the JES developer had had at his or her disposal a refactoring browser for Python, it would have at least been able to point out possible effects of renaming the variable behind this bug. Dynamic languages pose a particular challenge for building really useful static analysis tools, but we can still build tools to help.

But the developer might not use the refactoring browser. The change is so simple, a quick romp in emacs or vi is all we need, right? The compiler is a build tool; the programmer has to run it to create the executable. One approach that developers using dynamic languages can take is to use a build system that always runs the test suite. Another is to tool the version control system to run the tests before accepting the code at check-in. These tools more closely fulfill the role played by the compiler.

In response to another comment on his entry, Mark mentions a trade-off between process and language, a lá the familiar space-time trade-off among algorithms and data structures. This, I think, is the most interesting implication of his post. But the language in which we write code is just one tool that we use in building software. The compiler is another. So are editors, browsers, version control systems, build systems, and testing frameworks. The trade-off is between processes and tools.

This trade-off is one that seems to fly under most people's radar. The authors of the Agile Manifesto wrestle with the trade-off between caring for "individuals and interactions" and caring for "processes and tools". They come down on the side of individuals and interactions. But as I wrote a few weeks ago, valuing people over tools makes having the right tools even more important. I should probably have said "the right tools and process", because the process by which one works is just as important a part of the infrastructure that any programmer or creator needs. The question then becomes: In supporting individuals and interactions, how do we find the right balance between tools and process?

People characterize the different kinds of process available to programmers in a number of ways:

  • high ceremony versus low ceremony
  • heavy versus lightweight
  • sturdy versus agile

Some people assume that the righthand side of these choices require more discipline than the left, because the lefthand-style processes provide more rules to follow. That's not right. Discipline is, at best, orthogonal to this distinction. I think that the agile, lightweight, and low-ceremony approaches usually require more discipline, not less. In XP, you have to code in pairs, even if you think you don't need to. You have to run the tests. You have to refactor frequently and, on occasion, vigorously. You have to integrate code frequently. You have to take what you learn from all the practices and feed that back into the code. Easy? Not at all. Undisciplined? Not if you are practicing what you preach.

This sort of disciplined approach only works when the practices are at the level of granularity where they can become habit, part of one's muscle memory. It also works well only when supported by tools that make the process comfortable, almost disappear from conscious thought. Good tools shift as much of the burden of details and administrivia off of the programmer's mind and onto the tools that we use to write, build, test, share, and deliver our code.

I understand why many people want to use a compiler to support their process. But I still prefer to use languages that give me other kinds of freedom -- along with other tools that support my creative process.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

August 14, 2009 3:13 PM

Whither Programming?

I've been thinking a lot about the Software Engineering course I'm teaching this fall, which commences a week from Tuesday. Along the way, I have been looking at a lot of books and articles with "software engineering" in the title. It's surprising how few of them get any where near code. I know I shouldn't be surprised. I remember taking courses on software engineering, and I've stayed close enough to the area all these years to know what matters. There are issues other than programming that we need to think about while building big systems. And there is plenty of material out there about programming and programming tools and the nuts and bolts of programming.

Still, I think it is important when talking about software engineering to keep in mind what the goal is: a working program, or collection of programs. When we forget that, it's too easy to spin off into a land of un-reality. It's also important to keep in mind that someone has to actually write code, or no software will ever be engineered. I hope that the course I teach can strike a good balance.

In the interest of keeping code in mind, I share with you an assortment of programming news. Good, bad, ugly, or fun? You decide.

Hiding the Rainforest. Mark Guzdial reports that Georgia Tech is eliminating yet another language from its computing curriculum. Sigh. Thought experiments notwithstanding, variety in language and style is good for programmers. On a pragmatic note, someone might want to tell the GT folks that programming for the JVM may soon look more like Lisp and feel more like ML than Java or C++.

Programming meets the Age of Twitter. A Processing programming contest with a twist: all programs must be 200-characters or less. I'll give extra credit for any program that is a legal tweet.

Power to the Programmer! Phil Windley enjoys saving $60 by writing his own QIF->CSV converter. But the real hero is the person who wrote Finance::QIF.

Why Johnny Can't Read Perl. Courtesy of Lambda the Ultimate comes news we all figured had to be true: a formal proof that Perl cannot be parsed. Who said the Halting Theorem wasn't useful? I guess I'll stop working on my refactoring browser for Perl.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

August 13, 2009 3:51 PM

Keeping Things Visible

Via Jason Yip, this dandy story from a hospital president who favors process improvement Lean-style. It features Hideshi Yokoi, who is president of a Toyota production system support center in Kentucky:

... At one point, we pointed out a new information system that we were thinking of putting into place to monitor and control the flow of certain inventory. Mr. Yokoi's wise response, suggesting otherwise, was:

"When you put problem in computer, box hide answer. Problem must be visible!"

I have had many experiences, both personal and professional, in which putting something in a computer hides the problem from view and complicates finding the answer. Too often, when I decide to improve my process by putting data into my computer, I get so caught up in the rest of my tasks that I forget all about the problem. Tasks to do get lost in an ever-growing text file. Concerns about how we allocate merit pay get lost behind complex formulas in a spreadsheet that implement our current method. Scheduling and budget issues are lost in the last-minute details of readying this semester's spreadsheet for the next step in a university we don't control.

When you lose sight of a problem, it's hard to solve it. Moving things out of the daily clutter too easily becomes moving them out of our attention altogether.

I agree with Mr. Yokoi. A problem must be visible! But that cannot mean not using technology to automate and improve a process. Instead it means that we have to find ways to make the problem visible. JUnit was, for me, a great model. We needed to improve how we tested our programs, so we make the tests code. Rather than leave that code sitting lonely on disk, no better than textual documentation, we use a tool that runs the tests for us and tells what passes and what fails. Rather than leave that tool sitting lonely on disk, gathering dust because we forget to run the tests, we build running the tool into our development tools, where the tests can be run every time we save our changes or build our program. Make things visible.

We can avoid much of Mr. Yokoi's valid concern by changing our tools and our practices to ensure that problems don't disappear when we automate processes. That allows us to use computers to make us better.


Posted by Eugene Wallingford | Permalink | Categories: Managing and Leading, Software Development

August 12, 2009 5:01 PM

One Giant Leap for Computing

Charles Duke walking on the moon, Apollo 16

Last month, in honor of the Apollo 11 mission's fortieth anniversary, Google Code announced the open-sourcing of code for the mission's command and lunar modules. Very cool indeed. This project creates opportunities for many people. CS historians can add this code to their record of computing and can now study computing at NASA in a new way. Grady Booch will be proud. He has been working for many years on the task of preserving code and other historic artifacts of our discipline that revolve around software.

Software archeologists can study the code to find patterns and architectural decisions that will help us understand the design of software better. What we learn can help us do more, just as the Apollo 11 mission prepared the way for future visitors to the moon, such as Charles Duke of Apollo 16 (pictured here).

This code could help CS educators convince a few students to assembly language programming seriously. This code isn't Java or even C, folks. Surely some young people are still mesmerized enough by space travel that they would want to dig in to this code?

As a person who appreciates assembly-level programming but prefers working at a higher level, I can't help but think that it would be fun to reverse-engineer these programs to code at a more abstract level and then write compilers that could produce equivalent assembly that runs on the simulator. The higher-level programs created in this way would be a great way for us to record the architecture and patterns we find in the raw source.

Reading this code and about the project that surrounds it, I am in awe of the scale of the programming achievement. For a computer scientist, this achievement is beautiful. I'd love to use this code to share the excitement of computing with non-computer scientists, but I don't know how. It's assembly, after all. I'm afraid that most people would look at this code and say, "Um, wow, very impressive" while thinking, "Yet another example of how computer science is beyond me."

If only those people knew that many computer scientists feel the same way. We are in awe. At one level, we feel like this is way over our heads, too. How could these programmers done so much with so little? Wow. But then we take a breath and realize that we have the tools we need to dig in and understand how this stuff works. Having some training and experience, we can step back from our awe and approach the code in a different way. Like a scientist. And anyone can have the outlook of a scientist.

When I wonder how could the programmers of the 1960s could have done so much with so little, I feel another emotion, too: sheepishness. How far have we as a discipline progressed in forty years? Stepping back from the sheepishness, I can see that since that time programmers have created some astoundingly complex systems in environments that are as harsh or harsher than the Apollo programmers faced. It's not fair to glorify the past more than it deserves.

But still... Wow. Revisiting this project forty years later ought to motivate all of us involved with computer science in 2009 -- software professionals, academics, and students -- to dream bigger dreams and tackle more challenging projects.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

August 11, 2009 2:29 PM

Agile Moments: Evolution and Time

Evolution

The software engineering tip Every line of code is a user interface expresses several important ideas. Design matters. Names matter. Separating business logic from system wiring matters. Programs are read by people, so the code you write matters.

As I think about it, though, it embodies another important idea that is right up agile development's alley. We all know that programs tend to evolve over time, as user's needs and wants change. As developers, we also know that, as we build more systems in the same domain, we can evolve one-off programs toward a common framework. The framework generalizes over the separate programs, pulling the wiring out for maintenance in one place and for use in creating new programs in the same domain later.

What's interesting to me about the police database system described in that article is that it needed to evolve away from its built-in wiring and toward a more generic framework created in the outside world:

Specifically it wasn't Microsoft Access we had to worry about, but Ruby on Rails that provided 99% of all the infrastructure we'd built ourselves for an HTML-fronted database application.

It didn't have to be Rails, because web frameworks in other languages would probably have done as well for their shop. The point is, when the frameworks came along, their code was too tangled to easily take advantage of them. On the business side, another company could come along, replicate the business logic on top of one of the frameworks that provided the 99% infrastructure, and compete right away.

Is your design clean enough?

Time

I mentioned David Ogilvy's Confessions of an Advertising Man in a recent entry. Another passage from the book set of the alarm in my brain that watches for examples of shorter-than-usual iterations and continuous feedback:

Most young men in big corporations behave as if profit were not a function of time. When Jerry Lambert scored his first breakthrough with Listerine, he speeded up the whole process of marketing by dividing time into months. Instead of locking himself into annual plans, Lambert reviewed his advertising and his profits every month.

I guess that Lambert wasn't satisfied with halving his project length; he went straight to a factor of twelve. Feedback matters in the advertising game. In the same chapter of Confessions, Ogilvy talks about the importance of testing campaigns in front of real users. He claims that 24 out of 25 ideas will fail, so it's better to find out in testing than in production -- which both costs more and exposes the company to public failure. (Reputation matters a lot in the advertising game.)

Lambert's approach went further by monitoring projects that had already been deployed on a much shorter cycle and making decisions based on more frequent feedback about the projects. This reminded me of the approach suggested by Ricardo Semler in his talk Leading by Omission. Semler says that long-term plans, even yearly plans, are simply too large-grained to be useful. He advocates continuous feedback and monitoring.

Time is related to evolution, of course. When we operate at smaller units of time, we can evolve -- through both failure and success -- that much faster.

You don't need (or have to be) a special kind of leader, which Lambert and Semler seem to be, to benefit from this style. A disciplined process such as XP can guide you, and a team of developers operating from a set of agile principles can work to achieve similar goals.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

August 07, 2009 2:18 PM

A Loosely-Connected Friday Miscellany

An Addition to My News Aggregator

Thanks to John Cook, I came across the blog of Dan Meyers, a high school math teacher. Cook pointed to an entry with a video of Meyer speaking pecha kucha-style at OSCON. One of the important messages for teachers conveyed in this five minutes is Be less helpful. Learning happens more often when people think and do than when they follow orders in a well-defined script.

While browsing his archive I came across this personal revelation about the value of the time he was spending on his class outside of the business day:

I realize now that the return on that investment of thirty minutes of my personal time isn't the promise of more personal time later. ... Rather it's the promise of easier and more satisfying work time now.

Time saved later is a bonus. If you depend on that return, you will often be disappointed, and that feeds the emotional grind that is teaching. Kinda like running in the middle. I think it also applies more than we first realize to reuse and development speed in software.

Learning and Doing

One of the underlying themes in Meyers's writing seems to be the same idea in this line from Gerd Binnig, which I found at Physics Quote of Day:

Doing physics is much more enjoyable than just learning it. Maybe 'doing it' is the right way of learning ....

Programming can be a lot more fun than learning to program, at least the way we often try to teach it. I'm glad that so many people are working on ways to teach it better. In one sense, the path to better seems clear.

Knowing and Doing

One of the reasons I named by blog "Knowing and Doing" was that I wanted to explore the connection between learning, knowing, and doing. Having committed to that name so many years ago, I decided to stake its claim at Posterous, which I learned about via Jake Good. Given some technical issues with using NanoBlogger, at least an old version of it, I've again been giving some thought to upgrading or changing platforms. Like Jake, I'm always tempted to roll my own, but...

I don't know if I'll do much or anything more with Knowing and Doing at Posterous, but it's there if I decide that it looks promising.

A Poignant Convergence

Finally, a little levity laced with truth. Several people have written to say they liked the name of my recent entry, Sometimes, Students Have an Itch to Scratch. On a whim, I typed it into Translation Party, which alternately translates a phrase from English into Japanese and back until it reaches equilibrium. In only six steps, my catchphrase settles onto:

Sometimes I fear for the students.

Knowing how few students will try to scratch their own itches with their new-found power as a programmer, and how few of them will be given a chance to do so in their courses on the way to learning something valuable, I chuckled. Then I took a few moments to mourn.


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

August 06, 2009 11:59 AM

Woody Allen Is On Line 1

An excerpt from an interview at Gaping Void:

Some days, the work is tedious, labour-intensive and as repetitive as a production line in a factory. ... The key is having a good infrastructure. ...

But none of it works without discipline. Early on in my career, I was told that success demanded one thing above all others: turning up. Turning up every bloody day, regardless of everything.

This was said by artist Hazel Dooney, but it could just as well been said by a programmer -- or a university professor. One thing I love about the agile software world is its willingness to build new kinds of tools to support the work of programmers. Isn't it ironic? Valuing people over tools makes having the right tools even more important.


Posted by Eugene Wallingford | Permalink | Categories: General, Software Development

August 04, 2009 1:45 PM

Advice on my Advice to a Prospective Web Developers

Thanks to everyone who responded to my call for advice on what advice I should give to a student interested in studying at the university with a goal of becoming a web developer. People interpreted the article in lots of different ways and so were able to offer suggestions in many different ways.

In general, most confirmed the gist of my advice. Learn a broad set of technical skills from the spectrum of computer science, because that prepares one to contribute to the biggest part of the web space, or study design, because that's they part the techies tend to do poorly. A couple of readers filled me in on the many different kinds of web development programs being offered by community colleges and technical institutes. We at the university could never compete in this market, at least not as a university.

Mike Holmes wrote a bit about the confusion people have about computer science, with a tip of the hat to Douglas Adams. This confusion does play a role in prospective students' indecision about pursuing CS in college. People go through phases where they think of the computer as replacing an existing technology or medium: calculator, typewriter and printing press, sketchpad, stereo, television. Most of us in computer science seem to do one of two things: latch onto the current craze, or stand aloof from the latest trend and stick with theory. The former underestimates what computing can be and do, while the latter is so general that we appear not to care about what people want or need. It is tough to balance these forces.

In some twittering around my request, Wade Arnold tweeted about the technical side of the issue:

@wallingf Learn Java for 4 years to really know one language well. Then they will pick up php, ruby, or python for domain specific speed

The claim is that by learning a single language really well, a person really learns how to program. After that, she can learn other languages and fill in the gaps, both language-wise and domain-wise. This advice runs counter to what many, many people say, myself included: students should learn lots of different languages and programming styles in order to really learn how to program. I think Wade agrees with that over the long term of a programmer's career. What's unusual in his advice is the idea that a student could or should spend all four years of undergrad study mastering one language before branching out.

A lot of CS profs will dismiss this idea out of hand; indeed, one of the constant complaints one hears in certain CS ed circles is that too many schools have "gone Java" to the exclusion of all other languages and to the lasting detriment of their students. My department's curriculum has, since before I arrived, required students to study a single language for their entire first year, in an effort to help students learn one language well enough that they learn how to program before moving on to new languages and styles. When that language was, say, Pascal, students could pretty well learn the whole language and get a lot of practice using it. C is simple enough for that purpose, I suppose, but C++, Ada, and Java aren't. If we want students to master those languages at a comparable level, we might well need four years. I think that says more about the languages we use than about students learning enough programming in a year to be ready to generalize and fill in gaps with new languages and styles.

This entry has gotten longer than I expected, yet I have more to say. I'll write more in the days to come.


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

July 30, 2009 6:12 AM

Advice for a Prospective Web Developer

For the last couple of days, I've been speaking with a prospective non-traditional student who is seeking advice about what to study for a second bachelor's degree. His indecision about careers and school is worthy of its own post; I've seen it in so many other 20- and 30-somethings who are unhappy with their first careers and not sure of where to go next.

He wants to get into web development. What should he study? Well, he thinks he wants to get into web development, but he isn't sure exactly what it is. This is a common issue for prospective CS majors coming out of high school; they rarely know just what computer science is. It is apparently also an issue with the more visible discipline of web development. People see the products, but they are not sure at all how they are created. Is this a problem for budding electrical engineers or civil engineers?

This young man asked me for precise definitions of the terms "web design" and "web development", especially clear distinctions between the two, and a map from the terms onto specific undergrad majors. I explained that these are fuzzy terms, like so many of our best words and phrases. That didn't satisfy him much, because the fuzziness won't easily wipe away his indecision.

He is asking the head of the Computer Science department for advice, so I tell him what I think about web development, as fairly as I can, but with an unmistakeable fondness for my discipline. On the one hand, there is presentation, the web pages themselves and how they appear to users within a browser. On the other, there is the technology that underlies the web, the code and data that make it all work. To be versatile in the web game, and ultimately great, a person should learn both.

We do not offer a program in web development at my university, so a student must go to departments that teach the ideas and tools behind these facets of the web. I suggested graphic design with a little psychology for the presentation side, and computer science for the technology side. We have a excellent graphic design program here, and our CS program introduces students to programming and to the ideas of data structures, databases, algorithms, and information storage and retrieval that drive the web. We even teach an undergrad course in user interface design, which is the closest our major courses gets to presentation.

A freshman coming out of high school would do well to double-major in CS and graphic design. We have at least one such double-major now -- a dynamite student -- and a few others are thinking about taking this route. Majoring in both is a challenge, because it requires skills that are, on the surface, so unlike one another. I think the styles of thinking at the heart of these two disciplines are not so different after all. Besides, these majors don't just require skills; they help to develop them. It is a great double major.

However, most nontraditional students coming back to school are not interested in re-living the four- or five-year undergrad experience. They have lives to support, and often families, so they are usually focused on making a career change and getting on with it. As a result, one of these majors will have to do.

It seems to me that if you want to make a dent in the web world, you really want to know the technology and the ideas that make them work. Philip Greenspun teaches a software engineering course at MIT with web programming as its centerpiece, based in large part on the premise that this particular technology is so central to the experience of current CS grads when they get out in the world.

(I wonder what it would be like if I tried to teach Greenspun's course as my SE course?! My guess is that a lot of students would love it, a few would hate it, and the respective ratios for the faculty would be swapped.)

Not all students want to do the technology. I would rather students make this decision from a position of power -- knowing something about the technology -- than from a position of ignorance, but that's not always how the world works. Fine. Then the student can study graphic design and psychology and apply that knowledge to learning how to make web sites whose appearances sizzle. There is a shortage of great web sites out there, which tells me there may be a shortage of great web designers. Go for it.

I had to be honest. You can learn a lot about how to make websites at the tool level without giving any university a lot of money. With a high school degree and a few books on HTML, CSS, Javascript (three topics we teach in a course for non-majors), and maybe Flash (which we currently teach in an experimental course, also for non-majors), any reasonably intelligent person can become a competent web developer. This student already has a college degree, so with discipline and perseverance he could probably make this career shift on his own. There may be practical limitations on the career potential for some people who choose this path, but it's viable.

In at least two of my exchanges with this young man, I ran into a concern that I expected to encounter. It is the fear that rises to the top of almost every neophyte's mind whenever he or she is confronted with the words "computer science": Will I have to do much programming? I think he was asking as much about the jobs he would get in web development as about the CS courses he would have to take to get a major here.

My part of these conversations can be summed up in a mantra I now keep close to my heart:

You don't have to program; you get to program.

We need to do something to change the default expectation young people have about programming. Seriously.

This particular student is a reasonable young man. He is college-educated and earnest about finding a good career. He is also a little afraid. In my recent experience, I have encountered many like him, and I'd like to help them as best I can. So, let's get back to the original question, "What should a person study in college if she wants to get into web development?" Faithful readers: What should I tell them? What am I missing?


Posted by Eugene Wallingford | Permalink | Categories: Software Development

July 20, 2009 6:29 PM

Talking and Doing

I often find myself at meetings with administrator types, where I am the only person who has spent much time in a classroom teaching university students, at least recently. When talk turns to teaching, I sometimes feel like a pregnant woman at an ob-gyn convention. They may be part of a university and may even have taught a workshop or specialty course, but they don't usually know what it's like to design and teach several courses at a time, over many semesters in a row. That doesn't always stop them from having deeply-held and strong opinions about how to teach. Having been a student once isn't enough to know what it's like to teach.

I have had similar experiences as a university professor among professional software developers. All have been students and have learned something about teaching and learning from their time in school. But their lessons are usually biased by their own experiences. I was a student once, too, but that prepared me only a bit for being a teacher... There are so many different kinds of people in a classroom, so many different kinds of student. Not very many are just like me. (Thank goodness!)

Some software developers have taught. Many give half- or full-day tutorials at conferences. Others teach week-long courses on specific topics. A few have even taught a university course. Even still, I often don't feel like we are talking about the same animal when we talk about teaching. Teaching a training course for professional developers is not the same as teaching a university course to freshmen or even seniors. Teaching an upper-division or graduate seminar bears little resemblance to an elective course for juniors, let alone a class of non-majors. Even teaching such a course as an adjunct can't deliver quite the same experience as teaching a full load of courses across the spectrum of our discipline, day in and day out for a few years in a row. The principle of sustainable pace pops up in a new context.

As with administrators, lack of direct experience doesn't always stop developers from having deeply-held and strong opinions about what we instructors should be doing in the classroom. It creates an interesting dialectic.

That said, I try to learn whatever I can from the developers with whom I'm able to discuss teaching, courses, content, and curricula. One of the reasons I so enjoy PLoP, ChiliPLoP, and OOPSLA is having an opportunity to meet reflective individuals who have thought deeply about their own experiences as students and who are willing to offer advice on how I can do better. But I do try to step back from their advice and put it into the context of what it's like to teach in a real university, not one we've invented. Some ideas sound marvelous in the abstract but die a grisly death on the banks of daily university life. Revolution is easy when the battlefield is in our heads.

When it comes to working with software developers, I am more concerned that they will feel like the pregnant woman when they discuss their area of expertise with me and my university colleagues. One of my goals is not to be "that guy" when talking about software development with developers. I hope and prefer to speak out of personal and professional experience, rather than a theory I read in a book or a blog, or something another professor told me.

What we teach needs to have some connection to what developers do and what our students will need to do when they graduate. There is a lot more to a CS degree than just cutting code, but when we do talk about building software, we should be as accurate and as useful as we can be. This makes teaching a course like software engineering a bigger challenge for most CS profs than the more theoretical or foundational material such as algorithms or even programming languages.

One prescription is the same as above: I listen and try to learn whatever I can from developers when we talk about building software. Conferences like PLoP, ChiliPLoP, and OOPSLA give me opportunities I would not have otherwise, and I listen to alumni tell me about what they do -- and how -- whenever I can. I still have to sift what I learn into the context of the university, but it makes for great raw material.

Another prescription is to write code and use the tools and practices the people in industry use. Staying on top of that fast-moving game gets harder all the time. The world software is alive and changing. We professors have to keep at it. Mostly, it's a matter of us staying alive, too.


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

July 13, 2009 4:47 PM

Promotion from Tweet to Blog Entry

A couple of weeks ago, I quoted Glenn Vanderburg as my Tweet of the Day. Now he has made his tweet the set-up line in a full-blown blog entry, Sharp vs. Blunt Instruments:

Weak developers will move heaven and earth to do the wrong thing. You can't limit the damage they do by giving them less powerful tools. They'll just swing the blunt tools harder.

I still agree with the sentiment, as well as the bigger point: Give people powerful tools, teach them what you can, and let them create. The best programmers will do amazing things; the rest will be none the worse off. If you help to create a culture that values learning and encourages responsibility for others, you may even find some of the weak growing into amazing programmers, too.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

July 13, 2009 3:23 PM

Patterns as Compression Technology

In trying to understand the role patterns and pattern languages play both in developing software and in learning to develop software, I often look for different angles from which to look at patterns. I've written the idea of patterns as descriptive grammar and the idea of patterns as a source of freedom in design. Both still seem useful to me as perspectives on patterns, and the latter is among the most-read articles on my blog. The notion of patterns-as-grammar also relates closely to one of the most commonly-cited roles that patterns play for the developer or learner, that of vocabulary for describing the meaningful components of a program.

This weekend, I read Brian Hayes's instructive article on compressive sensing, The Best Bits. Hayes talks about how it is becoming possible to imagine that digital cameras and audio recorders could record compressed streams -- say, a 10-megapixel camera storing a 3MB photo directly rather than recording 30MB and then compressing it after the fact. The technique he calls compressive sensing is a beautiful application of some straightforward mathematics and a touch of algorithmic thinking. I highly recommend it.

While reading this article, though, the idea of patterns as vocabulary came to mind in a new way, triggered initially by this passage:

... every kind of signal that people find meaningful has a sparse representation in some domain. This is really just another way of saying that a meaningful signal must have some structure or regularity; it's not a mere jumble of random bits.

an optical illusion -- can you see it?

Programs are meaningful signals and have structure and regularity beyond the jumble of seemingly random characters at the level of the programming level. The chasm between random language stuff and high-level structure is most obvious when working with beginners. They have to learn that structure can exist and that there are tools for creating it. But I think developers face this chasm all the time, too, whenever they dive into a new language, a new library, or a new framework. Where is the structure? Knowing it is there and seeing it are too different matters.

The idea of a sparse representation is fundamental to compression. We have to find the domain in which a signal, whether image or sound, can be represented in as few bits as possible while losing little or even none of the signal's information. A pattern language of programs does the same thing for a family of programs. It operates at a level (in Hayes' terms, in a domain) at which the signal of the program can be represented sparsely. By describing Java's I/O stream library as a set of decorators on a set of concrete streams, we convey a huge amount of information in very few words. That's compression. If we say nothing else, we have a lossy compression, in that we won't be able to reconstruct the library accurately from the sparse representation. But if we use more patterns to describe the library (such as Abstract Class and "Throw, Don't Catch"), we get a representation that pretty accurately captures the structure of the library, if not the bit-by-bit code that implements it.

This struck me as a useful way to think about what patterns do for us. If you've seen other descriptions of patterns as a means for compression, I'd love to hear from you.


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

July 09, 2009 7:59 AM

Agile Moments: TDD and the Affordances of Programming

I recently ran across a link to a Dan Bricklin article from a few years ago, Why Johnny can't program. (I love the web!) Bricklin discusses some of the practical reasons why more people don't program. As he points out, it's not so much that people can't program as that they won't or choose not to program. Why? Because the task of writing code in a textual language isn't fun for everyone. What Bricklin calls "typed statement" programming fails all of Don Norman's principles of good design: visibility, good conceptual model, good mappings, and full and continuous feedback. Other programming models do better on these counts -- spreadsheets, rule-based expert system shells, WYSIWYG editors in which users generate HTML through direct manipulation -- and reach a wider audience. Martin Fowler recently talked about this style, calling it illustrative programming.

I had an agile moment as I read this paragraph from Bricklin about why debugging is hard:

One of the problems with "typed-statement" systems is that even though each statement has an effect, you only see the final result. It is often unclear which statement (or interaction of statements) caused a particular problem. With a "Forms" or direct manipulation system, the granularity is often such that each input change has a corresponding result change.

When we write unit tests for our code at about the same time we write the code, we improve our programming experience by creating intermediate results that help us to debug. But there's more. Writing tests helps us to construct a conceptual model of the program we are writing. They make visible the intended state of the program, and help us to map objects and functions in the code onto the behavior of the program at run-time. When we take small steps and run our tests frequently, they give us full and continuous feedback about the state of our program. Best of all, this understanding is recorded in the tests, which are themselves code!

In some ways, test-driven programming may improve on styles where we don't type statements. By writing tests, we participate actively in creating the model of our program. We are not simply passive users of someone else's constraint engine or inference engine. We construct our understanding as we construct our program.

Then again, some people don't need or want to write the reasoning component, so we need to provide access to tools they can use to be productive. Spreadsheets did that for regular folks. Scripting languages do it for programmers. Some people complain about scripting languages because they lack type safety, hide details, and are too slow. But the fact is that programmers are people, too, and they want tools that put them into a flow. They want languages that hit them in their sweet spot.

Bricklin concludes:

From all this you can see that the way a system requires an author to enter instructions into the computer affects the likelihood of acceptance by regular people. The more constrained the instructions the better. The more the instructions are clearly tied to various results the better. The more obvious and quickly the results may be examined the better.

TDD does all this, and more. It makes professional programmers more productive by providing better cognitive support for mental tasks we have to perform anyway. If we use TDD properly as we teach people to program, perhaps it can help us hit the sweet spot for more people, even in a "typed statement" environment.


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

July 03, 2009 8:31 AM

Thinking About Testing and Software Engineering

I've been buried in a big project on campus for the last few months. Yesterday, we delivered our report to the president. Ah, time to breathe, heading into a holiday weekend! Of course, next week I'll get back to my regular work. Department stuff. Cleaning my desk. And thinking about teaching software engineering this fall.

A bit of side reading found via my Twitter friends has me thinking about testing, and the role it will play in the course. In the old-style software engineering course, testing is a "stage" in the "process", which betrays a waterfall view of the world even when the instructor and textbook say that they encourage iterative development. But testing usually doesn't get much attention in such courses, maybe one chapter that describes the theory of testing and a few of the kinds of testing we need to do.

It seems to me that testing can take a bigger place in the course, if only because it exemplifies the sort of empiricism that we should all engage in as software developers. When we test, we run experiments to gather evidence that our program works as specified. We should adopt a similar mindset about how we build our programs. How do we know that our design is a good one? Or that our team is functioning well? Or that we are investing enough time and energy in writing tests and refactoring our code?

That's one reason I like Joakim Karlsson's post about the principle of locality in code changes. There may be ways that he can improve his analysis, but the most important thing about this post is that he analyzed code at all. He had a question about how code edits work, so he wrote a program to ask subversion repositories for the answer. That's so much better than assuming that his own hypothesis was correct, or that conventional wisdom was.

In regard to the testing process itself, Michael Feathers wrote a piece on "canalizing" design that points out a flaw in how we usually test our code. We write tests that are independent of one another in principle but that our test engines always run in the same order. This inadvertent weakness of sequential code creates an opportunity for programmers to write code that takes advantage of the implicit relationship between tests. But it's not really an advantage at all, because we then have dependencies in our code that we may not be aware of and which should not exist at all. Feathers suggests putting the tests in a set data structure and executing them them from there. At least then the code makes explicit that there is no implied order to the tests, which reminds the programmers who modify the code later that they should not depend on the order of test execution.

(I also like this idea for its suggestion that programs can and other should be dynamic structures, not dead sequences of text. Using a set of tests also moves us a step closer to making our code work well in a parallel environment. Explicit and implicit sequencing in programs makes it hard to employ the full power of multicore systems, and we need to re-think how we structure our programs if we want to break away from purely sequential machines. The languages guy in me sees some interesting applications of this idea in how write our compilers.)

Finally, I enjoyed reading Gojko Adzic's description of Keith Braithwaite's "TDD as if you mean it" exercise. Like the programming challenges I have described, it asks developers to take an idea to its extreme to break out of habits and to learn just how the idea feels and what it can give. Using tests to drive how the writing of code is more different from what most of us do than we usually realize. This exercise can help you to see just how different -- if you have an exercise leader like Keith to keep you honest.

However, I disagree with something Keith said in response to a comment about the relationship between TDD and functional programming:

I'm firmly convinced that sincere TDD leads one towards a functional style.

TDD will drive you to the style whose language you think.

There will be functional components to your solution to support the tests, and some good OOP has a functional feel. But in my experience you can end up with very nice objects in an object-oriented program as a result of faithfully-executed TDD.

Another of Braithwaite's comments saved the day, though. He credits Allan Watts for this line that captures his intent in designing exercises like this:

I came not as a salesman but as an entertainer. I want you to enjoy these ideas because I enjoy them.

Love this! He has a scholar's heart.

There is a lot more to testing that unit tests or regression testing. Finding ways to introduce students to the full set of ideas while also giving them a visceral sense of testing in the trenches is a challenge. I have to teach enough to prepare a general audience and also prepare students who will go on to take our follow-up course, Software Testing. That's a course that undergraduates at most schools don't have the opportunity to take, a strong point of our program. But that course can't be an excuse not to do testing well in the software engineering course. It's not a backstop; it's new ballgame.


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

June 25, 2009 9:48 PM

X of the Day

Quick hits, for different values of x, of course, but also different values of "the day" I encountered them. I'm slow, and busier than I'd like.

Tweet of the Day

Courtesy of Glenn Vanderburg:

Poor programmers will move heaven and earth to do the wrong thing. Weak tools can't limit the damage they'll do.

Vanderburg is likely talking about professional programmers. I have experienced this truth when working with students. At first, it surprised me when students learning OOP would contort their code into the strangest configurations not to use the OO techniques they were learning. Why use a class? A fifty- or hundred-line method will do nicely.

Then, students learning functional programming would seek out arcane language features and workarounds found on the Internet to avoid trying out the functional patterns they had used in class. What could have been ten lines of transparent Scheme code in two mutually recursive functions became fifteen or more of the most painfully tortured C code wrapped in a thin veil of Scheme.

I've seen this phenomenon in other contexts, too, like when students take an elective course called Agile Software Development and go out of their way to do "the wrong thing". Why bother with those unit tests? We don't really need to try pair programming, so we? Refactor -- what's that?

This feature of programmers and learners has made me think harder trying to help them see the value in just trying the techniques they are supposed to learn. I don't succeed as often as I'd like.

Comic of the Day

Hammock dwellers, unite!

2009-06-23 Wizard of Id on professors

If only. If only. When does summer break start?


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

June 17, 2009 9:48 PM

Another Connection to Journalism

a picture of Dave Winer

While reading about the fate of newspapers prior to writing my recent entry on whether universities are next, I ran across a blog entry by Dave Winer called If you don't like the news.... Winer had attended a panel discussion at the UC-Berkeley school of journalism. After hearing what he considered the standard "blanket condemnation of the web" by the journalists there, he was thinking about all the blogs he would love to have shown them -- examples of experts and citizens alike writing about economics, politics, and the world; examples of a new sort of journalism, made possible by the web, which give him hope for the future of ideas on the internet.

Here is the money quote for me:

I would also say to the assembled educators -- you owe it to the next generations, who you serve, to prepare them for the world they will live in as adults, not the world we grew up in. Teach all of them the basics of journalism, no matter what they came to Cal to study. Everyone is now a journalist. You'll see an explosion in your craft, but it will cease to be a profession.

Replace "journalism" with "computer science", and "journalist" with "programmer", and this statement fits perfectly with the theme of much of this blog for the past couple of years. I would be happy to say this to my fellow computer science educators: Everyone should now be a programmer. We'll see an explosion in our craft.

Will programming cease to be a profession? I don't think so, because there is still a kind and level of programming that goes beyond what most people will want to do. Some of us will remain the implementors of certain tools for others to use, but more and more we will empower others to make the tools they need to think, do, and maybe even play.

Are academic computer scientists ready to make this shift in mindset? No more so than academic journalists, I suspect. Are practicing programmers? No more so than practicing journalists, I suspect.

Purely by happenstance, I ran across another quote from Winer this week, one that expresses something about programming from the heart of a programmer:

i wasn't born a programmer.
i became one because i was impatient.
-- @davewiner

I suspect that a lot of you know just what he means. How do we cultivate the right sort of impatience in our students?


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

June 13, 2009 7:16 PM

Agile Moments While Reading the Newspaper

The first: Our local paper carries a parenting advice column by John Rosemond, an advocate of traditional parenting. In Wednesday's column, a parent asked how to handle a child who refuses to eat his dinner. Rosemond responded that the parents should calmly, firmly, and persistently expect the child to eat the meal -- even if it meant that the child went hungry that night by refusing.

[Little Johnny] will survive this ordeal -- it may take several weeks from start to finish -- with significantly lower self-esteem and a significantly more liberal palette, meaning that he will be a much happier child.

If you know Rosemond, you'll recognize this advice.

I couldn't help thinking about what happens when we adults learn a new programming style (object-oriented or functional programming), a new programming technique (test-driven development, pair programming), or even a new tool that changes our work flow (say, SVN or JUnit). Calm, firm, persistent self-discipline or coaching are often the path to success. In many ways, Rosemond's advice works more easily with 3- or 5-year-olds than college students or adults, because the adults have the option of leaving the room. Then again, the coach or teacher has less motivation to ensure the change sticks -- that's up to the learner.

I also couldn't help thinking how often college students and adults behave like 3- and 5-year-olds.

The second: Our paper also carries a medical advice column by a Dr. Gott, an older doctor who harkens back to an older day of doctor-patient relations. (There is a pattern here.) In Wednesday's column, the good doctor said about a particular diagnosis:

There is no laboratory or X-ray test to confirm or rule out the condition.

My first thought was, well, then how do we know it exists at all? This a natural reaction for a scientist -- or pragmatist -- to have. I think this means that we don't currently have a laboratory or X-ray test for the presence or absence of this condition. Or there may be another kind of test that will tell us whether the condition exists, such as a stress tests or an MRIs.

Without any test, how can we know that something is? We may find out after it kills the host -- but then we would need a post-mortem test. While the patient lives, there could be a treatment regimen that works reliably in face of the symptoms. This could provide the evidence we need to say that a particular something was present. But if the treatment fails, can we rule out the condition? Not usually, because there are other reasons that the treatment fails.

We face a similar situation in software with bugs. When we can't reproduce a bug, at least not reliably, we have a hard time fixing it. Whether we know the problem exists depends on which side of the software we live... If I am the user who encounters the problem, I know it exists. If I'm the developer, then maybe I don't. It's easy for me as developer to assume that there is something wrong with the user, not my lovingly handcrafted code. When the program involves threading or a complex web of interactions among several systems, we are more inclined to recognize that a problem exists -- but which problem? And where? Oh, to have a test... I can only think of two software examples of reliable treatment regimens that may tell us something was wrong: rebooting the machine and reinstalling the program. (Hey to Microsoft.). But those are such heavy-handed treatments that they can't give us much evidence about a specific bug.

There is, of course, the old saying of TDD wags: Code without a test doesn't exist. Scoff at that if you want, but it is a very nice guideline to live by.

To close, here are my favorite new phrases from stuff I've been reading:

Expect to see these jewels used in an article sometime soon.


Posted by Eugene Wallingford | Permalink | Categories: General, Software Development

June 05, 2009 3:25 PM

Paying for Value or Paying for Time

Brian Marick tweeted about his mini-blog post Pay me until you're done, which got me to thinking. The idea is something like this: Many agile consultants work in an agile way, attacking the highest-value issue they can in a given situation. If the value of the issues to work on decreases with time, there will come a point at which the consultant's weekly stipend exceeds the value of the work he is doing. Maybe the client should stop buying services at that point.

My first thought was, "Yes, but." (I am far too prone to that!)

First, the "yes": In the general case of consulting, as opposed to contract work, the consultant's run will end as his marginal effect on the company approaches 0. Marick is being honest about his value. At some point, the value of his marginal contribution will fall below the price he is charging that week. Why not have the client end the arrangement at that point, or at least have the option to? This is a nice twist on our usual thinking.

Now for the "but". As I tweeted back this feels a bit like Zeno's Paradox. Marick the consultant covers not half the distance from start to finish each week, but the most valuable piece of ground remaining. With each week, he covers increasingly less valuable distance. So our consultant, cast in the role of Achilles, concedes the race and says, okay, so stop paying me.

This sounds noble, but remember: Achilles would win the race. We unwind Zeno's Paradox when we realize that the sum of an infinite series can be a finite number -- and that number may be just small enough for Achilles to catch the tortoise. This works only for infinite series that behave in a particular way.

Crazy, I know, but this is how the qualification of the "yes" arose in my mind. Maybe, the consultant helps to create a change in his client that changes the nature of the series of tasks he is working on. New ideas might create new or qualitatively different tasks to do. The change created may change the value of an existing task, or reorder the priorities of the remaining tasks. If the nature of the series changes, it may cause the value of the series to change, too. If so, then the client may well want to keep the consultant around, but doing something different than the original set of issues would have called for.

Another thought: Assume that the conditions that Marick described do hold. Should the compensation model be revised? He seems to be assuming that the consultant charges the same amount for each week of work, with the value of the tasks performed early being greater than that amount and the value of the tasks performed later being less than that amount. If that is true,then early on the consultant is bringing in substantially more value than he costs. If the client pulls the plug as soon as the value proposition turns in its favor, then the consultant ends up receiving less than the original contract called for yet providing more than average value for the time period. If the consultant thinks that is fair, great. What if not? Perhaps the consultant should charge more in the early weeks, when he is providing more value, than in later week? Or maybe the client could pay a fee to "buy out" the rest of the contract? (I'm not a professional consultant, so take that into account when evaluating my ideas about consultant compensation...)

And another thought: Does this apply to what happens when a professor teaches a class? In a way, I think it does. When I introduce a new area to students, it may well be the case that the biggest return on the time we spend (and the biggest bang for the students' tuition dollars) happens in the first weeks. If the course is successful, then most students will become increasingly self-sufficient in the area as the semester goes on. This is more likely the case for upper-division courses than for freshmen. What would it be like for a student to decide to opt out of the course at the point where she feels like she has stopped receiving fair value for the time being spent? Learning isn't the same as a business transaction, but this does have an appealing feel to it.

The university model for courses doesn't support Marick's opt-out well. The best students in a course often reach a point where they are self-sufficient or nearly so, and they are "stuck". The "but" in our teaching model is that we teach an audience larger than one, and the students can be at quite different levels in background and understanding. Only the best students reach a point where opting out would make sense; the rest need more (and a few need a lot more -- more than one semester can offer!).

The good news is that the unevenness imposed by our course model doesn't hurt most of those best students. They are usually the ones who are able to make value out of their time in the class and with the professor regardless of what is happening in the classroom. They not only survive the latency, but thrive by veering off in their own direction, asking good questions and doing their own programming, reading, thinking outside of class. This way of thinking about the learning "transaction" of a course may help to explain another class of students. We all know students who are quite bright but end up struggling through academic courses and programs. Perhaps these students, despite their intelligence and aptitude for the discipline, don't have the skills or aptitude to make value out of the latency between the point they stop receiving net value and the end of the course. This inability creates a problem for them (among them, boredom and low grades). Some instructors are better able to recognize this situation and address it through one-on-one engagement. Some would like to help but are in a context that limits them. It's hard to find time for a lot of one-on-one instruction when you teach three large sections and are trying to do research and are expected to meet all of the other expectations of a university prof.

Sorry for the digression from Marick's thought experiment, which is intriguing in its own setting. But I have learned a lot from applying agile development ideas to my running. I have found places where the new twist helps me and others where the analogy fails. I'm can't shake the urge to do the same on occasion with how we teach.


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

May 28, 2009 10:02 PM

Developing Instinct

One of the challenges every beginner faces is learning the subtle judgments they must make. How much time will it take for us to implement this story? Should I create a new kind of object here? Estimation and other judgments are a challenge because the beginner lacks the "instinct" for making them, and the environment often does provide enough data to make a clear-cut decision.

I've been living with such a beginner's mind this week on my morning runs. Tuesday morning I started with a feeling of torpor and was sure I'd end with a slow time. When I finished, I was surprised to have run an average time. On Wednesday morning, I felt good yet came in with one of my slowest times for the distance ever. This morning, my legs were stiff, making steps seem a chore. I finished in one of my better times at this distance since working my mileage back up.

My inaccurate judgments flow out of bad instincts. Sometimes, legs feel slow and steps a challenge because I am pushing. Sometimes, I run with ease because I'm not running very hard at all!

At this stage in my running, bad instincts are not a major problem. I'm mostly just trying to run enough miles to build my aerobic base. Guessing my pace wrong has little tangible effect. It's mostly just frustrating not to know. Occasionally, though, the result is as bad as the judgment. Last week, I ran too fast on Wednesday after running faster than planned on Tuesday. I ended up sick for the rest of the week and missed out on 8-10 miles I need to build my base. Other times, the result goes the other way, as when I turned in a best-case scenario half-marathon in Indianapolis. Who knew? Certainly not me.

So, inaccurate instincts can give good or bad results. The common factor is unpredictability. That may be okay when running, or not; in any case, it can be a part of the continuous change I seek. But unpredictability in process is not so okay when I am developing software. Continuous learning is still good, but being wrong can wreak havoc on a timeline, and it can cause problems for your customer.

Bad instincts when estimating my pace wasn't a problem two years, though it has been in my deeper past. When I started running, I often felt like an outsider. Runners knew things that I didn't, which made me feel like a pretender. They had instincts about training, eating, racing, and resting that I lacked. But over time I began to feel like I knew more, and soon -- imperceptibly I began to feel like a runner after all. A lot -- all? -- of what we call "instinct" is developed, not inborn. Practice, repetition, time -- they added up to my instincts as a runner.

Time can also erode instinct. A lack of practice, a lack of repetition, and now I am back to where I was several years ago, instinct-wise. This is, I think, a big part of what makes learning to run again uncomfortable, much as beginners are uncomfortable learning the first time.

One of the things I like about agile approaches to software development is their emphasis on the conscious attention to practice. They encourage us to reflect about our practice and look for ways to improve that are supported by experience. The practices we focus on help us to develop good instincts: how much time it will take for us to implement a story, when to write -- and not write -- tests, how far to refactor a system to prepare for the next story. Developing accurate and effective instinct is one way we get better, and that is more important than being agile.

The traditional software engineering community thinks about this challenge, too. Watts Humphrey created the Personal Software Process to help developers get a better sense of how they use their time and to use this sense to get better. But, typically, the result feels so heavy, so onerous on the developers it aims to help, that few people are likely to stick with it when they get into the trenches with their code.

An aside: This reminds me of conversations I had with students in my AI courses back in the day. I asked them to read Alan Turing's classic Computing Machinery and Intelligence, and in class we discussed the Turing Test and the many objections Turing rebuts. Many students clung to the notion that a computer program could never exhibit human-like intelligence because humans lacked "gut instinct" -- instinct. Many students played right into Turing's rebuttal yet remained firm; they felt deeply that to be human was different. Now, I am not at ease with scientific materialism's claim that humans are purely deterministic beings, but the scientist in me tells me to strive for natural explanations of as much of every phenomenon as possible. Why couldn't a program develop a "gut feeling"? To the extent that at least some of our instincts are learned responses, developed through repetition and time, why couldn't a program learn the same instincts? I had fun playing devil's advocate, as I always do, even when I was certain that I was making little progress in opening some students' minds.

In your work and in your play, be aware of the role that practice, repetition, and time play in developing your instincts. Do not despair that you don't have good instincts. Work to develop them. The word missing from your thought is "yet". A little attention to your work, and a lot of practice, will go a long way. Once you have good instincts, cherish them. They give us comfort and confidence. They make us feel powerful. But don't settle. The same attention and practice will help you get better, to grow as a developer or runner or whatever your task.

As for my running, I am certainly glad to be getting stronger and to be able to run faster than I expect. Still, I look forward to the feeling of control I have when my instincts are more reliable. Unpredictable effort leads to unpredictable days.


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

May 20, 2009 4:26 PM

Bright Lines in Learning and Doing

Sometimes it pays to keep reading. Last time, I commented on breaking rules and mentioned a thread on the XP mailing list. I figured that I had seen all I needed there and was on the verge of skipping the rest. Then I saw a message from Laurent Bossavit and decided to read. I'm not surprised to learn something from Laurent; I have learned from him before.

Laurent's note introduced me to the legal term bright line. In the law, a bright-line rule is...

... a clearly defined rule or standard, composed of objective factors, which leaves little or no room for varying interpretation. The purpose of a bright-line rule is to produce predictable and consistent results in its application.

As Laurent says, Bright lines are important in situations where temptations are strong and the slope particularly steep, a well-known example is alcoholics' high vulnerability to even small exceptions. Test-driven development, or even writing tests soon after code and thus maintaining a complete suite of automated tests, requires a bright line for many developers. It's too easy to slide back into old habits, which for most developers are much older and stronger. Staying on the right side of the line may be the only practical way to Live Right.

This provides a useful name for what teachers often do in class: create bright lines for students. When students are first learning a new concept, they need to develop a new habit. A bright-line rule -- "Thou shalt always write a test first." or "Thou shalt write no line of code outside of a pair." -- removes from the students' minds the need to make a judgment that they are almost always not prepared to make yet: "Is this case an exception?" While learning, it's often better to play Three Bears and overdo it. This gives your mind a chance to develop good judgment through experience.

(For some reason, I am reminded of one way that I used to learn to play a new chess opening. I'd play a bazillion games of speed chess using it. This didn't train my mind to think deeply about the positions the opening created, but it gave me a bazillion repetitions. I soon learned a lot of patterns that allowed me to dismiss many bad alternatives and focus my attention on the more interesting positions.)

I often ask students to start with a bright line, and only later take on the challenge of a balancing test. It's better to evolve toward such complexity, not try to start there.

The psychological benefits of a bright-line test are not limited to beginners. Just as alcoholics have to hold a hard line and consider every choice consciously every day, some of us need a good "Thou shalt.." or "Thou shalt not..." in certain cases. As much as I like to run, I sometimes have to force myself out of bed at 5:00 AM or earlier to do my morning work-out. Why not just skip one? I am a creature of habit, and skipping even one day makes it even harder to get up the next, and the difficulty grows until I have a new habit.

(This has been one of the most challenging parts of trying to get back up to my old mileage after several extended breaks last year. I am proud finally to have done all five of my morning runs last week -- no days off, no PM make-ups. A new habit is in formation.)

If you know you have a particular weakness, draw a bright line for yourself. There is no shame in that; indeed, I'd say that it shows professional maturity to recognize the need and address it. If you need a bright line for everything, that may be a problem...

Sometimes, I adopt a bright line for myself because I want everyone on the team to follow a practice. I may feel comfortable exercising judgment in the gray area but not feel the rest of the team is ready. So we all play by the rules rather than discuss every possible judgment call. As the team develops, we can begin having those discussions. This is similar to how I teach many practices.

This may sound too controlling to you, and occasionally a student will say as much. But nearly everyone in class benefits from taking the more patient road to expertise. Again, from Laurent:

Rules which are more ambiguous and subtle leave more room for various fudge factors, and that of course can turn into an encouragement to fudge, the top of a slippery slope.

Once learners have formed their judgment, they are ready to balance forces. Until then, most are more likely to backslide out of habit than to make an appropriate choice to break the rule. And time spent arguing every case before they are ready is time not spent learning.


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

May 18, 2009 8:58 PM

Practice and Dogma in Testing

Shh.

I have a secret.

When I am writing a program, I will on occasion add a new piece of functionality without writing a test.

I am whispering because I have seen the reaction on the XP mailing list and on a number of blogs that Kent Beck received to his recent article, To Test or Not to Test? That's a Good Question. In this short piece, Kent describes his current thinking that, like golf, software development may have "long game" and "short game", which call for different tools and especially mentalities. One of the differences might be whether one is willing to trade automated testing for some other value, such as delivering a piece of software sooner.

Note that Kent did not say that in the long game he chooses not to test his code; he simply tested manually. He also didn't say that he plans never to write the automated tests he needs later; he said he would write them later, either when he has more time or, perhaps, when he has learned enough to turn 8 hours of writing a test into something much shorter.

Many peoples' public reactions to Kent's admission have been along these lines: "We test you to make this decision, Kent, but we don't trust everyone else. And by saying this is okay, you will contribute to the delinquency of many programmers." Now you know why I need to whisper... I am certainly not in the handful of programmers so good that these folks would be willing to excuse my apostasy. Kent himself is taking a lot of abuse for it.

I have to admit that Kent's argument doesn't seem that big a deal to me. I may not agree with everything he says in his article, but at its core he is claiming only that there is a particular context in which programmers might choose to use their judgment and not write tests before or immediately after writing some code. Shocking: A programmer should use his or her judgment in the course of acting professionally. Where is the surprise?

One of the things I like about Kent's piece is that he helps us to think about when it might be useful to break a particular rule. I know that I'll be breaking rules occasionally, but I often worry that I am surrendering to laziness or sloppiness. Kent is describing a candidate pattern: In this context, with these goals, you are justified in breaking this rule consciously. We are balancing forces, as we do all the time when building anything. We might disagree with the pattern he proposes, but I don't understand why developers would attack the very notion of making a trade-off that results in breaking a rule.

In practice, I often play a little loose with the rules of XP. There are a variety of reasons that lead me to do so. Sometimes I pay for not writing a test, and when I do I reflect on what about the situation made the omission so dangerous. If the only answer I can offer is "You must write the test, always.", then I worry that I have moved from behaving like a professional to behaving like a zealot. I suspect that a lot of developers make similar trade-offs.

I do appreciate the difficulty this raises for those of us who teach XP, whether at universities or in industry. If we teach a set of principles as valuable, what happens to our students' confidence in the principles when we admit that we don't follow the rules slavishly? Well, I hope that my students are learning to think, and that they realize any principle or rule is subject to our professional judgment in any given circumstance.

Of course, in the context of a course, I often ask students to follow the rules "slavishly", especially when the principles in question require a substantial change in how they think and behave. TDD is an example, as is pair programming. More broadly, this idea applies when we teach OOP or functional programming or any other new practice. (No assignment statements or sequences until Week 10 of Programming Languages!) Often, the best way to learn a new practice is to live it for a while. You understand it better then than you can from any description, especially how it can transform the way you think. You can use this understanding later when it comes to apply your judgment about potential trade-offs.

Even still, I know that, no matter how much an instructor encourages a new practice and strives to get students to live inside it for a while, some students simply won't do it. Some want to but struggle changing their habits. I feel for them. Others willfully choose not to try the something new and deny themselves the opportunity to grow. I feel for them, too, but in a different way.

Once students have had a chance to learn a set of principles and to practice them for a while, I love to talk with them about choices, judgment, and trade-offs. They are capable of having a meaningful discussion then.

It's important to remember that Kent is not teaching novices. His primary audience is professional programmers, with whom he ought to be able to have a coherent conversation about choices, judgment, and trade-offs. Fortunately, a few folks on the P list have entertained the "long game versus short game" claim and related their own experiences making these kind of decisions on a daily basis.

If we in the agile world rely on unthinking adherence to rules, then we are guilty of proselytizing, not educating. Lots of folks who don't buy the agile approaches love when they see examples of this rigidity. It gives them evidence to support their tenuous position about the whole community. From all of my full-time years in the classroom, I have learned that perhaps the most valuable asset I can possess is my students' trust in my goals and attitudes. Without that, little I do is likely to have any positive effect on them.

Kent's article has brought to the surfaced another choice agilistas face most every day: the choice between dogma and judgment. We tend to lose people when we opt for unthinking adherence to a rule or a practice. Besides, dogmatic adherence is rarely the best path to getting better every day at what we do, which is, I think one of the principles that motivate the agile methods.


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

May 15, 2009 8:30 PM

Robert's Rules of Order and Agile Forces

I am coming to a newfound respect for Robert's Rules of Order these days. I've usually shied away from that level of formality whenever chairing a committee, but I've experienced the forces that can drive a group in that direction.

For the last year, I have been chairing a campus-wide task force. Our topic is one on which there are many views on campus and for which there is not currently a shared vision. As a result, we all realized that our first priority was communication: discussing key issues, sharing ideas, and learning what others thought. I'll also say that I have learned a lot about what I think from these discussions. I've learned a lot about the world that lies outside of my corner of campus.

With sharing ideas and building trust as our first goals, I kept our meetings as unstructured as possible, even allowing conversations to drift off topic at times. That turned out well sometimes, when we came to a new question or a new answer unexpectedly.

We are nearing the end of our work, trying to reach closure on our descriptions and recommendations. This is when I see forces pushing us toward more structure. It is easy to keep talking, to talk around a decision so much that we find ourselves doubting a well-considered result, or even contradicting the it. At this point, we are usually cover well-trod ground. A little formality -- motion, second, discussion, vote, repeat -- may help. At least I now have some first hand experience of what might have led Mr. Robert to define his formal set of rules.

It occurs to me that Robert's Rules are a little like the heavyweight methodologies we often see in the software development world. We agile types are sometimes prone to look down on big formal methodologies as obviously wrong: too rigid, too limiting, too unrealistic. But, like the Big Ball of Mud, these methodologies came into being for a reason. Most large organizations would like to ensure some level of consistency and repeatability in their development process over time. That's hard to do when you have a 100 or a 1000 architects, designers, programmers, and testers. A natural tendency is to formalize the process in order more closely to control it. If you think you value safety more than discovery, or if you think you can control the rate of change in requirements, then a big process looks pretty attractive.

Robert's Rules looks like a solution to a similar problem. In a large group, the growth in communication overhead can outpace the value gained by lots of free-form discussion. As a group grows larger, the likelihood of contention grows as well, and that can derail any value the group might gain from free-form discussion. As a group reaches the end of its time together, free-form discussion can diverge from consensus. Robert's Rules seek to ensure that everyone has a chance to talk, but that the discussion more reliably reach a closing point. They opt for safety and lowering the risk of unpredictability, in lieu of discovery.

Smaller teams can manage communication overhead better than large ones. This is one of the key ideas behind agile approaches to software development: keep teams small so that they can learn at the same time they are making steady process toward a goal. Agile approaches can work in large organizations, too, but developers need to take into account the forces at play in larger and perhaps more risk-averse groups. That's where the sort of expertise we find in Jutta Eckstein's Agile Software Development in the Large comes in so handy.

While I sense the value of running a more structured meeting now, I don't intend to run any of my task force or faculty meetings using Robert's Rules any time soon. But I will keep in mind the motivation behind them and try to act in the spirit of a more directed discussion when necessary. I would rather still value people and communication over rules and formalisms, to the greatest extent possible.


Posted by Eugene Wallingford | Permalink | Categories: Managing and Leading, Patterns, Software Development

May 12, 2009 4:22 PM

Surprises, Problems, and Small Aircraft

Earlier today I listened to a TED talk by Tony Robbins. One snippet stood out. Here is a paraphrase, in part to clean up the language (because that's how I roll):

If I ask you whether you like variety, you'll say yes. Baloney. You like surprises you want. The others, you call problems.

Some people are better than others at accepting the surprises that they don't want. Perhaps that is why Robbins's anecdote reminded me of a story I read last summer in a book by John G. Miller called QBQ! The Question Behind the Question. The story, perhaps fictional, tells of a father and young daughter out for a fun plane ride one day, with dad behind the controls. When the plane's engine dies unexpectedly, dad turns to his daughter and says, calmly, I'm going to need to fly the plane differently.

I don't make generally New Year's resolutions, but when I am next tempted, I'll probably think again of this story. I want to be that guy, and I'm not.

----

(Quick book review: QBQ! is pretty standard for this genre of business self-help lit. It says a lot of things we all should already know, and probably do. But there are days when some of us need a reminder or a little pep talk. This book is full of short pep talks. It's a quick read and good enough at its task, as long as you remember that unless you change your behavior books like these are nothing but empty calories. A bit like software design methodologies.)


Posted by Eugene Wallingford | Permalink | Categories: Personal, Software Development

May 12, 2009 11:27 AM

Lessons from Compilers Course Experiment

Though final grades are not all yet submitted, the semester is over. We made adjustments to the specification in my compilers course, and the students were able to produce a compiler that produced compilable, executable Java code for a variety of source programs. For the most part, the issues we discussed most at their finals week demo dealt with quality control. We found some programs that confounded their parser or code generator, which were evidence of bits of complexity they had not yet mastered. There is a lesson to be learned: theory and testing often take a back seat to team dynamics and practices. Given the complexity of their source language, I was not too disappointed with their software, though I think this team fell short of its promise. I have been part of teams that have fallen similarly short and so can empathize.

So, what is the verdict on a couple of new ideas we tried this semester: letting the team design its own source language and working in a large team, of six? After their demo, we debriefed the project as a group, and then I asked them to evaluate the project and course in writing. So I have some student data on which to draw as well as my own thoughts.

On designing their own language: yes, but. Most everyone enjoyed that part of the project, and for some it was their favorite activity. But the students found themselves still churning on syntax and semantics relatively late into the project, which affected the quality and stability of their parser. We left open the possibility of small changes to the grammar as they learned more about the language by implementing it, but this element of reality complicated their jobs. I did not lock down the language soon enough and left them making decisions too late in the process.

One thing I can do the next time we try this is to put a firmer deadline on language design. One thing thing that the students and I both found helpful was writing programs in the proposed language and discussing syntactic and semantic language issues grounded in real code. I think I'll build a session or two of this into the course early, before the drop-dead date for the grammar, so that we can all learn as much as we can about the language before we proceed on to implementing it.

We also discussed the idea of developing the compiler in a more agile way, implementing beginning-to-end programs for increasing subsets of the language features until we are done. This may well help us get better feedback about language design earlier, but I'm not sure that it addresses the big risks inherent in letting the students design their own language. I'll have to think more on this.

On working is a team of size six: no. The team members and I were unanimous that a team of size six created more problems than it solved. My original thinking was that a larger team would be better equipped to do the extra work introduced by designing their own language, which almost necessarily delayed the start of the compiler implementation. But I think we were bitten by a preemptive variation of Brooks's Law -- more manpower slowed them down. Communication overhead goes up pretty quickly when you move from a team of three to a team of six, and it was much harder for the team to handle all of its members' ideas effectively. This might well be true for a team of experienced developers, but for a team of undergrads working on their first collaborative project of this scale, it was an occasional show-stopper. I'll know better next time.

As an aside, one feature the students included in the language they designed was first-class functions. This clearly complicated their syntax and their implementation. I was pleased that they took the shot. Even after the project was over and they realized just how much extra work first-class functions turned out to be, the team was nearly unanimous in saying that, if they could start over, they would retain that feature. I admire their spunk and their understanding of the programming power this feature gave to their language.


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

April 27, 2009 7:24 PM

Dynamic Scope as Bug or Feature

When I teach programming languages, we discuss the concepts of static and dynamic scoping. Scheme, like most languages these days, is statically scoped. This means that a variable refers to the binding that existed when the variable was created. For example,

> (define f
    (let ((i 100))
      (lambda (x)
        (+ x i))))
> (define i 1)
> (f 1)
101

This displays 101, not 2, because the reference to i in the body of function f is to the local variable i that exists when the function was created, not to the i that exists when the function is called. If the interpreter looked to the calling context to find its binding for i, that would be an example of dynamic scope, and the interpreter would display 2 instead.

Most languages use static typic these days for a variety of reasons, not the least of which is that it is easier for programmers to reason about code that is statically scoped. It is also easier to decompose programs and create modules that programmers can understand easily and use reliably.

In my course, when looking for an example of a dynamically-scoped language, I usually refer to Common Lisp. Many old Lisps were scoped dynamically, and Common Lisp gives the programmer the ability to define individual variables as dynamically-scoped. Lisp does not mean much to students these days, though. If I were more of a Perl programmer, I would have known that Perl offers the same ability to choose dynamic scope for a particular variable. But I'm not, so I didn't know about this feature of the language until writing this entry. Besides, Perl itself is beginning to fade from the forefront of students' attention these days, too. I could use an example closer to my students' experience.

A recent post on why Python does not optimize tail calls brought this topic to mind. I've often heard it said that in Python closures are "broken", which is to say that they are not closures at all. Consider this example drawn from the linked article:

IDLE 1.2.1      
>>> def f(x):
    if x > 0:
       return f(x-1)
    return 0;

>>> g = f >>> def f(x): return x

>>> g(5) 4

g is a function defined in terms of f. By the time we call g, f refers to a different function at the top level. The result is something that looks a lot like dynamic scope.

I don't know enough about the history of Python to know whether such dynamic scoping is the result of a conscious decision of the language designer or not. Reading over the Python history blog, I get the impression that it was less a conscious choice and more a side effect of having adopted specific semantics for other parts of the language. Opting for simplicity and transparency as an overarching sometimes means accepting their effects downstream. As my programming languages students learn, it's actually easier to implement dynamic scope in an interpreter, because you get it "for free". To implement static scope, the interpreter must go to the effort of storing the data environment that exists at the time a block, function, or other closure is created. This leads to a trade-off: a simpler interpreter supports programs that can be harder to understand, and a more complex interpreter supports programs that are easier to understand.

So for now I will say that dynamic scope is a feature of Python, not a bug, though it may not have been one of the intended features at the time of the language's design.

If any of your current favorite languages use or allow dynamic scope, I'd love to hear about it -- and especially whether and how you ever put that feature to use.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

April 17, 2009 8:20 PM

Slipping Schedules and Changing Scope in the Compiler Course

We have fallen behind in my compilers course. You may recall that before the semester I contemplated some changes in the course, including letting letting the students design their own language. My group of six chose that route, and as a part of that choice decided to work as a team of six, rather than in pairs or threes. This was the first time for me to have either of these situations in class, and I was curious to see how it would turn out.

Designing a language is tough, and even having lots of examples to work from, both languages and documents describing languages, is not enough to make it easy. We took a little longer than I expected. Actually, the team met its design deadline (with no time to spare, but...), but then followed a period of thinking more about the language. We both needed to come to a better understanding of the implications of some of their design decisions. Over time they changed their definition, sometimes refining and sometimes simply making the language different. This slowed the process of starting to implement the language and caused a few false starts in the scanner and parser.

Such bumps are a natural part of taking on the tougher problem of creating the language, so I don't mind that we are behind. I have learned a few things to do differently the next time a compiler class chooses this route. Working as a team of six increases the communication overhead they face, so I need to do a better job preparing them for the management component of such a large development project. It's hard for a team to manage itself, either through specific roles that include a nominal team leader or through town-hall style democracy. As the instructor, I need to watch for moments when the team needs me to take the rudder and guide things a bit more closely. Still, I think that this has been a valuable experience for the students. When they get out into industry, they will see successes and failures of the sort they've created for themselves this semester.

Still, things have gone reasonably well. It's almost inevitable that occasional disagreements about technical detail or team management will arise. People are people, and we are all hard to work with sometimes. But I've been happy with the attitude that all have brought to the project. I think all have shown a reasonable degree of commitment to the project, too, though they may not realize yet just what sort of commitment getting a big project like this done can require.

I have resisted the urge to tell (or re-tell?) the story of my senior team project: a self-selected team of good programmers and students who nonetheless found ways to fall way behind their development schedule. We had no way to change the scope of the system, struggled mightily in the last weeks of the two-term project, and watched our system crash on the day of the acceptance test. The average number of hours I spent on this project during its second term? 62 hours. And that was while taking another CS course, two accounting courses, and a numerical analysis course -- the final exam for which I have literally no recollection of at all, because by that time I was functioning on nearly zero sleep for days on end. This story probably makes me sound crazy -- not committed, but in need of being committed. Sometimes, that's what a project takes.

On the technical side, I will do more next time to accelerate our understanding of the new language and our fixing of the definition. One approach I'm considering is early homework assignments writing programs in the new language, even before we have a scanner or parser. This causes us all to get concrete sooner. Maybe I will offer extra-credit points to students who catch errors in the spec or in others students' programs. I'll definitely give extra-credit for catching errors in my programs. That's always fun, and I make a perfect foil for the class. I am sure both to make mistakes and to find holes in their design or their understanding of it.

But what about this semester? We are behind, with three weeks to D-Day. What is the best solution?

The first thing to recognize is that sometimes this sort of thing happens. I do not have the authority to implement a death march, short of becoming an ineffective martinet. While I could try telling students that they will receive incompletes until the project is finished, I don't really have the authority to push the deadline of the project beyond the end of our semester.

The better option is one not made available to my project team in school, but which we in the software world now recognize as an essential option: reduce the scope of the project. The team and I discussed this early in the week. We can't do much to make the language smaller, because it is already rather sparse in data types, primitive operators, and control structure. The one thing we could drop is higher-order procedures, but I was so please when they included this feature that I would feel bad watching it drop out now. But that would not really solve our problem. I am not sure they could complete a compiler for the rest of the language in time anyway.

We decided instead to change the target language from JVM bytecodes to Java itself. This simplifies what remains for them quite a bit, but not so much that it makes the job easy. The big things we lose are designing and implementing a low-level run-time system and emitting machine-level code. The flip side is that we decided to retain the language's support for higher-order procedures, which is not trivial to implement in generated Java code. They'll still get to think about and implement closures, perhaps using anonymous inner classes to implement function arguments and results.

This results in a different challenge, and a change in the experience the students will have. The object lesson is a good one. We have made a trade-off, and that is the nature of life for programmers. Change happens, and things don't always proceed according to plan. So we adapt and do the best we can. We might even spend 60 hours one week working on our project!

For me, the biggest effect of the change is on our last two and a half weeks of lecture. Given where we are and what they will be doing, what do they most need to learn? What ideas and techniques should they see even if they won't use them in their compilers? I get to have some fun right up to the end, too.


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

April 15, 2009 9:00 PM

Should Code Die On Schedule?

Last evening, Mike Feathers tweeted a provocative idea: The world might be better if all code disappeared at a fix age and we had to constantly rewrite it. Heck, he could even write a tool to seek and destroy all code as it reaches the age of three months. Crazy, huh?

Maybe this idea is not so crazy. At my university and most other places, hardware is on a 3- or 4-year "replacement cycle". Whether we need new computers in our student labs, we replace them on a schedule. Why? Because we recognize that hardware reaches a natural "end of life". Using it beyond that time means that we carry an ever-increasing risk that it will fail. Rather than let it fail and be caught without for a short while, we accept the upfront cost of replacing it with newer, more reliable, better equipment. The benefit is piece of mind, and more reliable performance.

Maybe we should recognize that software can be like hardware. It reaches a natural "end of life" -- not because physical components wear out, but because the weight of changing requirements and growing desires push it farther out of compliance with reality. (This is like when we replace a computer because its processor speed and RAM size fall out of compliance with reality: the demands of new operating systems and application software.) Using software beyond its natural end of life means that we carry an ever-increasing risk of failure -- when it actually breaks, or when we "suddenly" need to spend major time and money to "maintain" it. Rather than risk letting our software fail out from under us, we could accept the cost of replacing it with newer, more reliable, better software.

One of the goals of the agile software development community is to reduce the cost of changing our code. If agile approaches are successful, then we might be more willing to bear the risk of our code falling away from reality, because we are not afraid of changing it. (Agile approaches also value continuous feedback, which allows us to recognize the need for change early, perhaps before it becomes too costly.) But there may be times or environments in which these techniques don't work as well as we like.

Suppose that we committed to rewriting 1/4 of every system every year. This would allow graceful, gradual migration to new technologies. A possible cost of this strategy is increasing complexity, because our systems would come to be amalgams of two, three, or even four technologies and programming languages interoperating in one system. But is this all that much different from life now? How many of our systems already consist of modules in several languages, several technologies, several styles?

Another side of me is skeptical. Shouldn't our programs just keep working? Why not take care to design them really well? Why not change small parts of the system as needed, rather than take on wholesale changes we don't need yet? Doesn't this approach violate the principle of YAGNI?

Another advantage of the approach: It gives us a built-in path to continuous learning. Rewriting part of a system means digging into the code, learning or re-learning what it's made of and how it works. With pair programming, we could bring new people into a deeper understanding of the code. This would help us to increase the feeling of collective code ownership, as well as preserving and replenishing corporate memory.

Another disadvantage of the approach: It is hard to maintain this sort of discipline in hard financial times. We see this with hardware, too. When money is short, we often decide to lengthen or eliminate the replacement cycle. In such times, my colleagues who traffic in computer labs and faculty desktop computers are a little more worried than usual; what happens if... Software development seems always to be under financial pressure, because user demands grow to outpace our capacity to produce meet them. Even if we decided to try this out for software, administration might immediately declare exigency and fall back into the old ways: build new systems, now, now, now.

Even after thinking about the idea for a while now, it still sounds a little crazy. Then again, sometimes crazy ideas have something to teach us. It is not so crazy that I will dismiss it out of hand. Maybe I will try it some time just see how it works. If it does, I'll give Mike the credit!


Posted by Eugene Wallingford | Permalink | Categories: Software Development

April 14, 2009 7:49 PM

Posts of the Day

... for a definition of "the day" that includes when I read them, not when the authors posted them.

Tweet of the Day

Marick's Law: In software, anything of the form "X's Law" is better understood by replacing the word "Law" with "Fervent Desire".
-- Brian Marick

I love definitions that apply to themselves. They are the next best thing to recursion. I will have plenty of opportunities to put Brian's fervent desire into practice while preparing to teach software engineering this fall.

Non-Tech Blog of the Day

I don't usually quote former graffiti vandals or tattoo artists here. But I am an open-minded guy, and this says something that many people prefer not to hear. Courtesy of Michael Berman:

"Am I gifted or especially talented?" Cartoon said. "No. I got all this through hard work. Through respecting my old man. From taking direction from people. From painting when everyone else was asleep. I just found something I really love and practiced at it my whole life."
-- Mister Cartoon

Okay, so I am tickled to have quoted a guy named Mister Cartoon. His work isn't my style, but his attitude is. Work. Respect. Deference. Practice. Most days of the week, I would be well-served by setting aside my hubris and following Mister Cartoon's example.


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

April 12, 2009 6:46 PM

Language Driving Programming

William Stafford's Writing the Australian Crawl includes several essays on language, words, and diction in poetry. Words and language -- he and others say -- are co-authors of poems. Their shapes and sounds drive the writer in unexpected ways and give rise to unexpected results, which are the poems that they needed to write, whatever they had in mind when they started. This idea seems fundamental to the process of creation for most poets.

We in CS think a lot about language. It is part of the fabric of our discipline, even when we don't deal in software. Some of us in CS education think and talk way too much about programming languages: Pascal! Java! Ada! Scheme!

But even if we grant that there is art in programming and programs, can we say that language drives us as we build our software? That language is the co-author of our programs? That its words and shapes (and sounds?) drive the programmer in unexpected ways and gives rise to unexpected results, which are the programs we need to write, whatever we have in mind when we start? Can the programmer's experience resemble in any way the poet's experience that Stafford describes?

[Language] begins to distort, by congealing parts of the total experience into successive, partially relevant signals.... [It] begins to enhance the experience because of a weird quality of language: the successive distortions of language have their own cumulative potential, and under certain conditions the distortions of language can reverberate into new experiences more various, more powerful, and more revealing than the experiences that set off language in the first place.

Successive distortions with cumulative potential... Programmers tend not to like it when the language they use, or must use, distorts what they want to say, and the cumulative effects of such distortions in a program that can give us something that feels cumbersome, feels wrong, is wrong.

Still... I think of my experiences coding in Smalltalk and Scheme, and recall hearing others tell similar tales. I have felt Smalltalk push me towards objects I wasn't planning to write, even to objects of a kind I had previously been unaware. Null objects, and numbers as control structures; objects as streams of behavior. Patterns of object-oriented programs often give rise to mythical objects that don't exist in the world, which belies OOP's oft-stated intention to build accurate models of the world. I have felt Scheme push me toward abstractions I did not know existed until just that moment, abstractions so abstract that they make me -- and many a programmer already fearful of functional style -- uncomfortable. Yet it is simply the correct code to write.

For me: Smalltalk and Lisp and Scheme, yes. Maybe Ruby. Not Java. C?

Is my question even meaningful? Or am I drowning in my own inability to maintain suitable boundaries between things that don't belong together?


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

April 09, 2009 7:48 PM

Musings on Software, Programming, and Art

My in-flight and bedtime reading for my ChiliPLoP trip was William Stafford's Writing the Australian Crawl, a book on reading and especially writing poetry, and how these relate to Life. Stafford's musings are crashing into my professional work on the trip, about solving problems and writing programs. The collisions give birth to disjointed thoughts about software, programming, and art. Let's see what putting them into words does to them, and to me.

Intention endangers creation.

An intentional person is too effective to be a good guide in the tentative act of creating.

I often think of programming as art. I've certainly read code that felt poetic to me, such as McCarthy's formulation of Lisp in Lisp (which I discussed way back in an entry on the unity of data and program. But most of the programs we write are intentional: we desire to implement a specific functionality. That isn't the sort of creation that most artists do, or strive to do. If we have a particular artifact in mind, are we really "creating"?

Stafford might think not, and many software people would say "No! We are an engineering discipline, not an artistic one." Thinking as "artists", we are undisciplined; we create bad software: software that breaks, software that doesn't serve its intended purpose, software that is bad internally, software that is hard to maintain and modify.

Yet many people I know who program know... They feel something akin to artistry and creation.

How can we impress both sides of this vision on people, especially students who are just starting out? When we tell only one side of the story, we mislead.

Art is an interaction between object and beholder.

Can programs be art? Can a computer system be art? Yes. Even many people inclined to say 'no' will admit, perhaps grudgingly, that the iPod and the iPhone are objects of art, or at least have elements of artistry in them. I began writing some of these notes on the plane, and all around me I see iPods and iPhones serving people's needs, improving their lives. They have changed us. Who would ever have thought that people would be willing to watch full-length cinematic films on a 2" screen? Our youth, whose experiences are most shaped by the new world of media and technology, take for granted this limitation, as a natural side effect of experiencing music and film and cartoons everywhere.

Yet iPods aren't only about delivering music, and iPhones aren't just ways to talk to our friends. People who own them love the feel of these devices in their hands, and in our lives. They are not just engineered artifacts, created only to meet a purely functional need. They do more, and they are more.

Intention endangers creation.

Art reflects and amplifies experience. We programmers often look for inspirations to write programs by being alert to our personal experience and by recognizing disconnects, things that interrupt our wholeness.

Robert Schumann said, To send light into the darkness of men's hearts -- such is the duty of the artist. Artists deal in truth, though not in the direct, assertional sense we often associate with mathematical or scientific truth. But they must deal in truth if they are to shine light into the darkness of our hearts.

Engineering is sometimes defined as using scientific knowledge and physical resources to create artifacts that achieve a goal or meet a need. Poets use words, not "physical resources", but also shapes and sounds. Their poems meet a need, though perhaps not a narrowly defined one, or even one we realize we had until it was met in the poem. Generously, we might think of poets as playing a role somewhat akin to the engineer.

How about engineers playing a role somewhat akin to the artist? Do engineers and programmers "send light into the darkness of men's hearts"? I've read a lot of Smalltalk code in my life that seemed to fill a dark place in my mind, and my soul, and perhaps even my heart. And some engineered artifacts do, indeed, satisfy a need that we didn't even know we had until we experienced them. And in such cases it is usually experience in the broadest sense, not the mechanics of saving a file or deleting our e-mail. Design, well done, satisfies needs users didn't know they had. This applies as well to the programs we write as to any other artifact that we design with intention.

I have more to write about this, but at this time I feel a strong urge to say "Yes".


Posted by Eugene Wallingford | Permalink | Categories: General, Software Development

April 08, 2009 6:32 PM

Quick Hits on the Way Out of Dodge

Well, Carefree. But it plays the Western theme to the hilt.

This was a shorter conference visit than usual. Due to bad weather on the way here, I arrived on the last flight in on Sunday. Due to work constraints of my workshop colleagues, I am heading out before the Wednesday morning session. Yet it was a productive trip -- like last year, but this time on our own work, as originally planned. We produced

  • the beginnings of a catalog of data-driven real-world problems used in CS1 courses across the country, and
  • half of a grant proposal to NSF's CPATH program, to fund some of our more ambitious ideas about programming for everyone, including CS majors.
A good trip.

Yesterday over our late afternoon break, we joined with the other workshop group and had an animated discussion started by a guy who has been involved with the agile community. He claimed that XP and other agile approaches tell us that "thinking is not allowed", that no design is allowed. A straw man can be fun and useful for exploring the boundaries of a metaphor. But believing it for real? Sigh.

A passing thought: Will professionals in other disciplines really benefit from knowing how to program? Why can't they "just" use a spreadsheet or a modeling tool like Shazam? This question didn't come to mind as a doubt, but as a realization that I need a variety of compelling stories to tell when I talk about this with people who don't already believe my claim.

While speaking of spreadsheets... My co-conspirator Robert Duvall was poking around Swivel, a web site that collects and shares open data sets, and read about the founders' inspiration. They cited something Dan Bricklin said about his own inspiration for inventing the spreadsheet:

I wanted to create a word processor for data.

Very nice. Notice that Bricklin's word processor for data exposes a powerful form of end-user programming.

When I go to conferences, I usually feel as if the friends and colleagues I meet are doing more, and more interesting, things than I -- in research, in class, in life. It turns out that a lot of my friends and colleagues seem to think the same thing about their friends and colleagues, including me. Huh.

I write this in the air. I was booked on a 100% full 6:50 AM PHX-MSP flight. We arrive at the airport a few minutes later than planned. Rats, I have been assigned a window seat by the airline. Okay, so I get on the plane and take my seat. A family of three gets on and asks me hopefully whether there is any chance I'd like an aisle seat. Sure, I can help. (!) I trade out to the aisle seat across the aisle so that they can sit together. Then the guy booked into the middle seat next to me doesn't show. Surprise: room for my Macbook Pro and my elbows. Some days, the smile on me in small and unexpected ways.


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

April 03, 2009 1:24 PM

Debugging by Biction

Gus Mueller, creator of one of my favorite tools, VoodooPad, recently wrote a short note on debugging his designs and programs:

I learned a long time ago that the two best debugging tools I own are a nice piece of paper, and a good pencil.

Bic pens

Writing something down is a great way to "think out loud". My Ghostbusters-loving colleague, Mark Jacobson, calls this biction. He doesn't define the term on his web page, though he does have this poetic sequence:

Bic pen, ink flowing, snow falling, writing, thinking, playing, dancing

That sounds fanciful, but biction is a nuts-and-bolts idea. The friction of that Bic pen on the paper is when ideas that are floating fuzzily through the mind confront reality.

Mark and I taught a data structures course together back in the 1990s, and we had a rule: if students wanted to ask one of us a question, they had to show us a picture they had drawn that illustrated their problem: the data structure, pointers, a bit of code, ... If nothing else, this picture helped us to understand their problem better. But it usually offered more. In the process of showing us the problem using their picture, students often figured out the problem in front of our eyes. Other students commented that, while drawing a picture in preparing to ask a question, they saw the answer for themselves. Biction.

Of course, one can also "think out loud" out loud. In response to my post on teaching software engineering, a former student suggested that I should expose my students to pair programming, which he found "hugely beneficial" in another course's major project, or at least to rubber duck debugging. That's biction with your tongue.

It may be that the most important activity happens inside our heads. We just need to create some friction for our thoughts.


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

March 31, 2009 6:43 AM

Teaching Software Engineering

We offer a lot of our upper-division courses on a three-semester rotation. For the last few years, I have been teaching Programming Languages and our compilers course as a part of our rotation. Before I became department head, I taught Algorithms -- a course I love -- in the third slot. I passed the course on to someone else my first semester as head, and I've never gotten it back. The person who teaches it now is really good, and this leaves me to be a utility infielder, covering whatever most needs to be covered that semester. I've taught our intro course in this slot, as well as a set of 1-credit courses on individual programming languages.

This fall, I will teach a course I have never taught before: software engineering. This is a traditional introduction to the discipline for juniors and seniors:

Study of software life cycle models and their phases -- planning, requirements, specifications, design, implementation, testing, and maintenance. Emphasis on tools, documentation, and applications.

I have taught non- traditional software engineering before, in the form of two offerings of a course on agile software development. In fact, I taught that course during my first full semester after starting this blog, and it -- along with and sometimes in tandem with training for my second marathon -- provided a wealth of inspiration for my writing.

Long-term readers of this blog know that I have expressed skepticism about the software engineering metaphor, both in general and in some of the specifics, such as gathering requirements. Still, I respect the goals of the discipline and the effort and earnestness of its proponents. I also am able to put aside philosophical concerns in the interest of department concerns. We all agree that developing software, especially in the large, is a challenging endeavor that requires knowledge and skill. That is the goal of our course, and it will be the goal of my offering this fall.

The course I teach needs to stay pretty close to the traditional notion of software engineering, because that's what our curriculum calls for. By most accounts, employers who hire our students are pretty happy with what we teach in the course, in particular the breadth of exposure we give them. This is one of the constraints I face as I plan.

That said, I will certainly teach my own course. I will make sure that students are exposed to the agile approaches. Many of our alumni have told me that their employers are introducing elements of XP or Scrum into their software development processes, and that they wish they had learned a bit about them during their undergraduate studies. This is the right place for them to encounter agile principles and practices, as a different perspective on the phases of the software lifecycle.

I also tend more toward the working-code end of the spectrum, whereas this course has historically tended toward the modeling-and-abstraction end. I'd like to find a way to ensure that students see and experience both. Models are nothing more than pictures on a whiteboard or in a CASE tool until we can implement them in code. Besides, our students seem to graduate with an alarming lack of exposure to modern tools for version control, build management, and testing. I'd like to find a way for them to learn not only what the stages of software development are but also tools and practices for effectively evolving programs through those stages.

I'm looking for papers and ideas that can help me design a good course that balances several of these forces. Karen Reid's and Greg Wilson's Learning by doing is a great exemplar; it talks about how to introduce version control by using a tool like CVS or SVN to deliver, manage, and collect student assignments.

In the end, I want this course to serve well students wherever they end up after graduation, whether at a big-process company such as Rockwell Collins or a mostly-agile shop consisting of a few developers. Most of our graduates will end up working in several different development environments within a few years, regardless of where they land, so broad principles and understanding trump mastery of any particular skill set. But I also know that mastery plays a big role in how they will come to understand the principles.

Whatever I do, I want the course to be real, not merely an academic exercise.

My daily bleg: please send me any thoughts you have on this course, ways to organize it, or tools to use. As always, I value your suggestions and will gladly share the credit!


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

March 24, 2009 6:13 AM

Adele Goldberg, Computer Scientist and Entrepreneur

My slogan is:
computing is too important to be left to men.

-- Karen Sparck-Jones, 1935-2007

We talk a lot about the state of women in computing. Girls have deserted computer science as an academic major in recent years, and female undergrad enrollment is at a historic low relative to boys. Some people say, "Girls don't like to program," but I don't think that explains all of the problem. At least a few women agree with me... During a session of the Rebooting Computing Summit in January, one of the men asserted that girls don't like to program, and one of the women -- Fran Allen, I think -- asked, "Says who?" From the back of the room, a woman's voice called out, "Men!"

A lot of people outside of computer science do not know how much pioneering work in our discipline was done by women. Allen won a Turing Award for her work on languages and compilers, and the most recent Turing Award was given to Barbara Liskov, also for work in programming languages. Karen Sparck-Jones, quoted above, discovered the idea of inverse document frequency, laying the foundation for a generation of advances in information retrieval. And these are just the ones ready at hand; there many more.

Adele Goldberg

When people assert that women don't like (just) to program, they usually mean that women prefer to do computer science in context, where they can see and influence more directly the effects that their creations will have in the world. One of my heroes in computing, Adele Goldberg, has demonstrated that women can like -- and excel -- on both sides of the great divide.

(Note: I am not speaking of this Adele Goldberg, who is, I'm sure, a fine computer scientist in her own right!)

Goldberg is perhaps best known as co-author of several books on Smalltalk. Many of us fortunate enough to come into contact with Smalltalk back in the 1980s cut our teeth on the fabulous "blue book", Smalltalk-80: The Language and Its Implementation. You can check out a portion of the blue book on-line. This book taught many a programmer how to implement a language like Smalltalk. It is still one of the great books about a language implementation, and it still has a lot to teach us a lot about object-oriented languages.

But Goldberg didn't just write about Smalltalk; she was in the lab doing the work that created it. During the 1970s, she was one of the principal researchers at Xerox PARC. The team at PARC not only developed Smalltalk but also created and experimented with graphical user interfaces and other features of the personal computing experience that we all now take for granted.

Goldberg's legacy extends beyond the technical side of Smalltalk. She worked with Alan Kay to develop an idea of computing as a medium for everyone and a new way for young people to learn, using the computer as a dynamic medium. They described their vision in Personal Dynamic Media, a paper that appeared in the March 1977 issue of IEEE Computer. This was a vision that most people did not really grasp until the 1990s, and it inspired many people to consider a world far beyond what existed at the time. But this paper did not just talk about vision; it also showed their ideas implemented in hardware and software, tools that children were already using to create ideas. When I look back at this paper, it reminds me of one reason I admire Goldberg's work: it addresses both the technical and the social, the abstract and the concrete, idea and implementation. She and Kay were thinking Big Thoughts and also then testing them in the world.

(A PDF of this paper is currently available on-line as part of the New Media Reader. Read it!)

After leaving PARC, Goldberg helped found ParcPlace, a company that produced a very nice Smalltalk product suitable for corporate applications and CS research alike. The Intelligent Systems Lab I worked in as a grad student at Michigan State was one of ParcPlace's first clients, and we built all of our lab's software infrastructure on top of its ObjectWorks platform. I still have ObjectWorks on 3.5" floppies, as well as some of the original documentation. (I may want to use it again some day...)

Some academics view founding a business as antithetical to the academic enterprise, or at least as not very interesting, but Goldberg sees it as a natural extension of what computer science is:

The theoretical and practical knowledge embodied in CS is interesting as standalone study. But the real opportunity lies in equipping oneself to partner with scientists or business experts, to learn what they know and, together, to change how research or business is conducted.

(I found this quote as a sidebar in Women in Computing -- Take 2, an article in a recent issue of Communications of the ACM.)

I suppose that the women-don't-like-to-program crowd might point to Goldberg's career in industry as evidence that she prefers computing in its applied context to the hard-core technical work of computer science, but I don't think that is true. Her work on Smalltalk and real tools at PARC was hard-core technical, and her work at ParcPlace on Smalltalk environments was hard-core technical, too. And she has the mentality of a researcher:

Don't ask whether you can do something, but how to do it.

When no one knows the answer, you figure it out for yourself. That's what Goldberg has done throughout her career. And once she knows how, she does it -- both to test the idea and make it better, and to get the idea out into the world where people can benefit from it. She seems to like working on both sides of the divide. No, she would probably tell us that the divide is an artificial barrier of our own making, and that more of us should be doing both kinds of work.

When we are looking for examples of women who have helped invent computer science, we find researchers and practitioners. We find women working in academia and in industry, working in technical laboratories and in social settings where applications dominate theory. We don't have to limit our vision of what women can do in computing to any one kind of work or work place. We can encourage young women who want to be programmers and researchers, working on the most technical of advances. We can encourage young women who want to work out in the world, changing how people do what they do via the dynamic power of software. If you are ever looking for one person to serve as an example of all these possibilities, Adele Goldberg may be the person you seek.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

March 20, 2009 9:09 PM

At Least It's Not Too Easy

Tim Bray talks about how photography is too easy to learn:

Quoting from About Photography (1949) by American photographer Will Connell (hat tip Brendan MacRae): "Every medium suffers from its own particular handicap. Photography's greatest handicap is the ease with which the medium as such can be learned. As a result, too many budding neophytes learn to speak the language too long before they have anything to say."

Programming doesn't seem to suffer from this problem! Comments to Bray's entry about books like "C for Dummies" notwithstanding, there are not many people walking around who think programming is too easy. Mark Guzdial has described the reaction of students taking a non-majors course with a computational economics theme when they found out they would have to do a little scripting in Python. Most people who do not already have an interest in CS express disdain for programming's complexity, or fear of it. No one likes to feel stupid. Perhaps worst of all, even students who do want to major in CS don't want to program.

We in the business seem almost to have gone out of our way to make programming hard. I am not saying that programming is or can be "easy", but we should stop erecting artificial barriers that make it harder than it needs to be -- or that create an impression that only really smart people can write code. People who have ideas can write. We need to extend that idea to the realm of code. We cannot make professional programmers out of everyone, any more than piano and violin lessons can make professional musicians out of everyone. But we ought to be able to do what music teachers can do: help anyone become a competent, if limited, practitioner -- and come to appreciate the art of programming along the way.

The good news is that we can solve this "problem", such as it is. As Guzdial wrote in another fine piece:

An amazing thing about computing is that there are virtually no ground rules. If we don't like what the activity of programming is like, we can change it.

We need to create tools that expose powerful constructs to novices and hide the details until later, if they ever need to be exposed. Scratch and Alice are currently popular platforms in this vein, but we need more. We also need to connect the ability to program with people's desires and interests. Scripting Facebook seems like the opportunity du jour that is begging to be grasped.

I'm happy to run across good news about programming, even if it is only the backhanded notion that programming is not too easy. Now we need to keep on with the business of making certain that programming is not too hard.


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

March 09, 2009 3:26 PM

Sweating The Small Stuff

On Learning Curves, I read a lament about calculus students having a hard time putting their skills into practice on some basic word problems. This line stood out:

They can do the calculus. The algebra slays them.

Of late, our CS faculty have been discussing a programming corollary. Students have passed their intro programming course and a data structures course. They get to an intermediate programming course, or a programming languages course, or an AI course, where they learn some more advanced design idea or algorithm. They answer conceptual courses about the material on exams and do well. Then they try to write code... and hit a wall.

Sometimes a new programming language gets in the way, but sometimes not -- students are using a language they used for a year in the intro sequence. And whether it's a new language or an old one, the problems seem ticky-tack: semicolons, declarations, function calls.

They can talk about the advanced concepts, but simple programming tasks to implement the ideas slays them. The programming part looks like attention to detail to me, or effort spent to internalize basic grammar and vocabulary. One prof half-jokingly says his students have gone out of their way to forget what they already knew.

You don't really know programming unless you can write a program from a real problem, and not just a tightly-specified exercise designed by the instructor. And I'm not sure you can really know a concept -- not in the way that a computer scientist needs to know it -- unless you can write a program using it for a real problem. If syntax is in the way, you simply need to buckle down and learn the syntax.

I don't have any answers on this but thought it was interesting that a calculus prof is running into the same kind of problem.


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

February 25, 2009 6:45 PM

Notes for Students Working on Projects

My compiler students are getting to the point where they should be deep in writing a parser for their language. Walking back from lunch, I was thinking about some very simple things they could do to make their lives -- and project -- better.

1.   Start.

Yes, start. If you read the literature of the agile software development world or even of the life hacker world, people talk about the great power that comes just from taking the first step. I've always loved the old Goethe quote about the power of committing to a course of action. But isn't this all cliché?

It is so easy to put off tracing your language grammar, or building those FIRST and FOLLOW sets, or attacking what you know will be a massive parsing table. It is so easy to be afraid of writing the first line of code because you aren't sure what the whole app will look like.

Take the first step, however small and however scary. I'm always amazed how much more motivated I feel once I break the seal on a big task and have some real feedback from my client or my compiler.

2.   Always have live code.

Live code is always better than ideas in your head. Brian Marick tells us so. One of the Gmail guys tells us so:

We did a lot of things wrong during the 2.5 years of pre-launch Gmail development, but one thing we did very right was to always have live code. ...

Of course none of the code from my prototype ever made it near the real product (thankfully), but that code did something that fancy arguments couldn't do (at least not my fancy arguments), it showed that the idea and product had real potential.

Your code can tell which ideas are good ones and which are bad ones. It can teach you about the app you are building. It can help you learn what your user wants.

I hear this all the time from students: "We have a pretty good handle on this, but no code yet." Sounds good, but... Live code can convince your professor that you really have done something. It can also help you ask questions and be submitted on the due date. Don't underestimate the value in that.

As Buchheit says from the Gmail experience, spend less time talking and more time prototyping. You may not be Google, but you can realize the same benefits as those guys. And with version control you don't have to worry about taking the wrong step; you can always back up.

3.   Don't forget what you know.

Okay, I have to admit that this did not occur to me on my walk home form lunch. This afternoon, a former student and local entrepreneur gave a department seminar on web app security. He twice mentioned that many of the people he hires have learned many useful skills in object-oriented design and software engineering, using system languages such as Java and Ada. When they get to his shop, they are programming in a scripting language such as PHP. "And they throw away all they know!" They stop using the OOP principles and patterns they have learned. They stop documenting code and testing. It's as if scripting occurs in a different universe.

As he pointed out after the talk, all of those skills and techniques and practices matter just as much -- no, more -- when using a language with many power tools, few boundaries, and access to all of his and his clients' data and filesystem.

When building a compiler in class, or any other large-scale team project in a capstone course, all of those skills and techniques and practices matter, too, and sometimes for the first time in student's career. This is likely the largest and most sophisticated program they have ever written. It is the first time they have ever had to depend on one or two or five other students to get done, to understand and work with others' code, to turn their own code other for the understanding and use of their teammates.

There is a reason that you are learning all this stuff. It's for the project you are working on right now.


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

February 24, 2009 12:01 PM

Even More on Programming and Computational Thinking

Confluence... The Education column in the February 2009 issue of Communications of the ACM, Human Computing Skills: Rethinking the K-12 Experience, champions computational thinking in lieu of programming:

Through the years, despite our best efforts to articulate that CS is more than "just programming," the misconception that the two are equivalent remains. This equation continues to project a narrow and misleading image of our discipline -- and directly impacts the character and number of students we attract.

I remain sympathetic to this concern. Many people, including lost potential majors, think that CS == programming. I don't know any computer scientists who think that is true. I'd like for people to understand what CS is and for potential majors who end up not wanting to program for a living to know that there is room for them in our discipline. But pitching programming to the aside altogether is the wrong way to do that, and will do more harm than good -- even for non-computer scientists.

It seems to me that the authors of this column conflate CS with programming at some level, because they equate writing a program with "scholarly work" in computer science:

While being educated implies proficiency in basic language and quantitative skills, it does not imply knowledge of or the ability to carry out scholarly English and mathematics. Indeed, for those students interested in pursuing higher-level English and mathematics, there exist milestone courses to help make the critical intellectual leaps necessary to shift from the development of useful skills to the academic study of these subjects. Analogously, we believe the same dichotomy exists between CT, as a skill, and computer science as an academic subject. Our thesis is this: Programming is to CS what proof construction is to mathematics and what literary analysis is to English.

In my mind, it is a big -- and invalid -- step from saying "CT and CS are different" to saying that programming is fundamentally the domain of CS scholars. I doubt that many professional software developers will agree with a claim that they are academic computer scientists!

I am familiar with Peter Naur's Programming as Theory Building, which Alistair Cockburn brought to the attention of the software development world in his book, Agile Software Development. I'm a big fan of this article and am receptive to the analogy; I think it gives us an interesting way to look at professional software development.

But I think there is more to it than what Naur has to say. Programming is writing.

Back to the ACM column. It's certainly true that, at least for many areas of CS, "The shift to the study of CS as an academic subject cannot .. be achieved without intense immersion in crafting programs." In that sense, Naur's thesis is a good fit. But consider the analogy to English. We all write in a less formal, less intense way long before we enter linguistic analysis or even intense immersion in composition courses. We do so as a means of communicating our ideas, and most of us succeed quite well doing so without advanced formal training in composition.

How do we reach that level? We start young and build our skills slowly through our K-12 education. We write every year in school, starting with sentences and growing into larger and larger works as we go.

I recall that in my junior year English class we focused on the paragraph, a small unit of writing. We had written our first term papers the year before, in our sophomore English course. At the time, this seemed to me like a huge step backward, but I now recognize this as part of the Spiral pattern. The previous year, we had written larger works, and now we stepped back to develop further our skills in the small after seeing how important they were in the large.

This is part of what we miss in computing: the K-8 or K-12 preparation (and practice) that we all get as writers, done in the small and across many other learning contexts.

Likewise, I disagree that proof is solely the province of mathematics scholars:

Just as math students come to proofs after 12 or more years of experience with basic math, ...

In my education, we wrote our first proofs in geometry -- as sophomores, the same year we wrote our first term papers.

I do think one idea from the article and from the CT movement merits more thought:

... programming should begin for all students only after they have had substantial practice acting and thinking as computational agents.

Practice is good! Over the years, I have learned from CS colleagues encountered many effective ways to introduce students, whether at the university or earlier, to ideas such as sorting algorithms, parallelism, and object-oriented programming by role play and other active techniques -- through the learner acting as a computational agent. This is an area in which the Computational Thinking community can contribute real value. Projects such as CS Unplugged have already developed some wonderful ways to introduce CT to young people.

Just as we grow into more mature writers and mathematical problem solvers throughout our school years, we should grow into more mature computational thinkers as we develop. I just don't want us to hold programming out of the mix artificially. Instead, let's look for ways to introduce programming naturally where it helps students understand ideas better. Let's create languages and build tools to make this work for students.

As I write this, I am struck by the different nouns phrases we are using in this conversation. We speak of "writers", not "linguistic thinkers". People learn to speak and write, to communicate their ideas. What is it that we are learning to do when we become "computational thinkers"? Astrachan's plea for "computational doing" takes on an even more XXXXX tone.

Alan Kay's dream for Smalltalk has always been the children could learn to program and grow smoothly into great ideas, just as children learn to read and write English and grow smoothly into the language and great ideas of, say, Shakespeare. This is a critical need in computer science. The How to Design Programs crowd have shown us some of the things we might do to accomplish this: language levels, tool support, thinking support, and pedagogical methods.

Deep knowledge of programming is not essential to understand all basic computer science, some knowledge of programming adds so very much even to our basic ideas.


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

February 09, 2009 4:31 PM

Embracing Failure

A while back, I clipped this quote from a university publication, figuring it would decorate a blog entry some day:

The thing about a liberal arts education ... is it prepares you to fail successfully and learn from that failure. ... You will all fail. That's OK.

-- Jim Linahon

Linahon is an alumnus of our school who works in the music industry. He gave a talk on campus for students aspiring to careers in the industry, the theme of which was, "Learn to fail. It happens"

More recently, I ran across this as the solution to a word puzzle in our local paper:

You've got to jump off cliffs all the time and build your wings on the way down.

-- Ray Bradbury

Bradbury was one of my favorite authors when I was growing up (The Martian Chronicles mesmerized me!) This quote goes farther than Linahon's: what other people call failure is learning to fly. Do not fear.

A comment made at the Rebooting Computing summit about "embracing failure" brought these quotes back to mind, along with an e-mail message Rich Pattis wrote sometime last year. Rich talked about how hard our discipline must feel to beginners, because it is a discipline learned almost wholly by failure. Learning to program can seem like nothing more than an uninterrupted sequence failures: syntax errors, logic errors, boundary cases, ugly interface, .... I'm not a novice any more, but I still feel the constant drip of failure whenever I work on a piece of code I don't already understand well.

The thing is, I kinda like that feeling -- the challenge of scaling a mountain of code. My friends who program can at least say that they don't mind it, and the best among them seem to thrive in such an environment. I think that's part of what separates programmers from less disturbed people.

Then again, repeated failure is a part of learning many things. Learning to play a musical instrument or a sport require repeated failure for most people. Hitting a serve in tennis, or a free throw on the hardcourt, or a curve ball in baseball -- the only way to learn is by doing it over and over, failing over and over, until the mind and body come together in a memory that make success a repeatable process. This seems to be an accepted part of athletics, even among the duffers who only play for fun. How many people in America are on a golf course this day, playing the game poorly but hoping -- and working -- to get better?

Why don't we feel the same way about academics, and about computer programming in particular? Some small number seem to, maybe the 2% that Knuth said are capable of getting it.

I have heard some people say that in sports we have created mechanisms for "meaningful failure", though I'm not sure exactly what that means, but I suspect that if we could build tools for students and set problems before them that give them a sense of meaningful failure, we'd probably not scare off so many people from our early courses. I suspect that this is part of what some people mean when they say we should make our courses more fun, though thinking in terms of meaningful failures might give us a better start on the issue than simply mantras about games and robots.

I don't think just equating programming to sports is enough. Mitch Wand sent a message to the PLT Scheme mailing list this weekend on a metaphor he has been using to help students want to stick to the design recipes of How to Design Programs:

In martial arts, the first thing you learn is to do simple motions very precisely. Ditto for ballet, where the first thing you learn is the five positions.

Once those are committed to muscle memory, you can go on to combinations and variations.

Same deal for programming via HtDP: first practice using the templates until you can do it without thinking. Then you can go on to combinations and variations.

I like the analogy and have used a similar idea with students in the past. But my experience is that this only works for students who want to learn to programming -- or martial arts or ballet, for that matter. If you start with people who want to go through the process of learning, then lots of things can work. The teacher just needs to motivate the student every once in a while to stick with the dream. But it's already their dream.

Maybe the problem is that people want to play golf and the martial arts -- for whatever social, business, or masochistic reasons -- but that most people don't want to learn to program? Then our problem comes back to a constant theme on this blog: putting a feeling of power in peoples' hands when we show them programming, so they want to endure the pain.

One last quote, in case you ever are looking for a literary way to motivate students to take on tough challenges rather than little ones that acquiesce easily and making us feel good sooner:

What we choose to fight is so tiny!
What fights us is so great!
...
When we win it's with small things,
and the triumph itself makes us small.
...
Winning does not tempt that man.
This is how he grows: by being defeated, decisively,
by constantly greater beings.

This comes from Rainer Maria Rilke's The Man Watching. What a marvelous image, growing strong by being beaten -- decisively, less -- by ever greater opponents. I'm sure you professional programmers who have been tackling functional programming, continuations, Scheme, Haskell, and Erlang these last few years know just the feeling Rilke describes, deep in the marrow of your bones.


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

January 23, 2009 1:02 PM

Design in Agile Methods

I recently read an early version of a paper by a colleague in the agile world that talks about several different ways he approaches design problems. I like that he is writing about design. After all these years, I still encounter many people who think this statement is an axiom:

agile development → no design

In those situations, I try to share (gently) my experience as developer and occasional consultant, but the notion is pretty well ingrained. As I wrote last month, it's hard a slog.

As I read the preprint, I thought more about doing design in a reactive way, responding to new features as we add them to our code. My skeptical colleagues think that the sort of design so many of us do in agile settings is not design at all. But I think they are wrong, and the word "reactive" brought to mind a similar notion from my days in AI: reactive planning.

When I first heard that term in a graduate readings course, it sounded like an oxymoron to me. Planning is the opposite of reaction, right? If an agent does not construct a plan, then how is it planning? Reactive planning contrasts with what then came to be known as classical planning. An agile wag wag might coin the term "BPUF" -- big planning up-front.

But I learned about the idea and found it wasn't an oxymoron at all, that reactive planning was a real and valuable way for an agent to prepare its actions. I have learned the same is true of "reactive" design. We folks in the agile world probably haven't done enough to teach agile novices to design in this way, which is one reason I'm hoping to see more papers like the draft I just read.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

January 07, 2009 6:18 PM

Looking Ahead -- To Next Week

The latest edition of inroads, the quarterly publication of SIGCSE, arrived in my mailbox yesterday. The invited editorial was timely for me, as I finally begin to think about teaching this spring. Alfred Aho, co-author of the dragon book and creator of several influential languages and programming tools, wrote about Teaching the Compilers Course. He didn't write a theoretical article or a solely historical one, either; he's been teaching compilers every semester for the last many years at Columbia.

As always, I enjoyed reading what an observant mind has to say about his own work. It's comforting to know that he and his students face many of the same challenges with this course as my students and I do, from the proliferation of powerful, practical tools to the broad range of languages and target machines available. (He also faces a challenge I do not -- teaching his course to 50-100 students every term. Let's just say that my section this spring offers ample opportunity for familiarity and one-on-one interaction!)

Two of Aho's ideas are now germinating in my mind as I settle on my course. The first is something that has long been a feature of my senior project courses other than compilers: an explicit focus on the software engineering side of the project. Back when I taught our Knowledge-Based Systems course (now called Intelligent Systems) every year, we paid a lot of attention to the process of writing a large program as a team, from gathering requirements and modeling knowledge to testing and deploying the final system. We often used a supplementary text on managing the process of building KBS. Students produced documents as well as code and evaluated team members on their contributions and efforts.

When I moved to compilers five or six years ago after a year on sabbatical, I de-emphasized the software engineering process. First of all, I had smaller classes and so no teams of three, four, or five. Instead, I had pairs or even individuals flying solo. Managing team interactions became less important, especially when compared to the more intellectually daunting content of the compiler course. Second, the compiler students tended to skew a little higher academically, and they seemed to be able to handle more effectively the challenge of writing a big program. Third, maybe I got a little lazy and threw myself into the fun content of the course, where my own natural inclinations lie.

Aho has his students work in teams of five and, in addition to writing a compiler and demoing at the end of the semester:

  • write a white paper on their source language,
  • write a tutorial on using it, and
  • close with a substantial project report written by every member of the team.

This short article has reawakened my interest in having my students -- many of whom will graduate into professional careers developing software and managing its development -- attend more to process. I'll keep it light, but these three documents (white paper, tutorial, and project report) will provide structure to tasks the students already have to do, such as to understand their source language well and to explore the nooks and crannies of its use.

The second idea from Aho's article is to have students design their own language to compile. This is something I have never done. It is also a feature that brings more value to the writing of a white paper and a tutorial for the language. I've always given students a language loosely of my own design, adapted from the many source languages I've encountered in colleagues' courses and professional experience. When I design the language, I have to write specs and clarifications; I have to code sample programs to demonstrate the semantics of the language and to test the students' compilers at the end of the semester.

I like the potential benefits of having students design their own language. They will encounter some of the issues that the designers of the languages they use, such as Java, C++, and Ada faced. They can focus their language in a domain or a technology niche of interest to them, such as music and gaming or targeting a multi-core machine. They may even care more about their project if they are implementing an engine that makes their own creation come to life.

If I adopt these course features, they will shift the burden between instructor and student in some unusual ways. Students will have to exert more energy into the languages of the course and write more documentation. I will have to learn about their languages and follow their projects much more intimately as the semester proceeds in order to be able to provide the right kind of guidance at the right moments. But this shift, while demanding different kinds of work on both our parts, should benefit both of us. When I design more of the course upfront, I have greater control over how the projects proceed. This gives me a sense of comfort but deprives the students of experiences with language design and evolution that will serve them well in their careers. The sense of comfort also deprives me of something: the opportunity to step into the unknown in real-time and learn. Besides, my students often surprise me with what they have to teach me.

As I said, I'm just now starting to think about my course in earnest after letting Christmas break be a break. And I'm starting none to soon -- classes begin Monday. Our first session will not be until Thursday, however, as I'll begin the week at the Rebooting Computing summit. This is not the best timing for a workshop, but it does offer me the prospect of a couple of travel days away from the office to think more about my course!


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

December 05, 2008 4:59 PM

Agile Fading?

An acquaintance of mine sent a link to James Shore's The Decline and Fall of Agile to a mailing list with a warning: "You probably don't want to read it if you're a follower of the religion." His use of the pejorative reveals that he's not a fan. He is a strong believer in design -- if not BDUF, at least more than he perceives agile methods to encourage. I read Shore's articles anyway, so I was happy to now.

I don't think of myself as religious on this matter, but I often speak positively about agile approaches (I might say "fairly") when a colleague expresses what I think os a misconception, so here goes...

Shore is right. He also echoes something that comes up every so often when I am discussing agile approaches with folks who have had a bad experience: When a company does something it calls "agile" but which is unsound (perhaps because they leave something important out), things usually do not go well. But that's because they've done something unsound, not because they call what they did "agile".

I really try not to be a knee-jerk apologist for agile methods. They don't solve every problem in the world; nothing does. So when someone tells me that agile has failed them, I try to listen carefully to what they've been doing. Otherwise, it's too easy to say, "Oh, you did it wrong." That's the sort of behavior that leads people to talk about religion. And it's intellectually sloppy, which bothers me more.

But sometimes people do have a misconception, or do leave out an essential practice, or do something else that counters the desired benefit. When someone tells me,

[Extreme Programming] says you should spend no more than 10 minutes on design during a three-week sprint. 10 minutes!

... I have to say something. Maybe some agile evangelists have said this; maybe not. But it's wrong, and someone has to say so.

For what it's worth, my understanding of XP goes back to the original spirit: If doing something is valuable, then why not do it all the time? As a result, I encourage the teams I work with at the university and in industry to think about design all the time. But I also encourage them not to design too far ahead of their code base, because that is too often untested thought. Refactoring, a practice that some design-oriented people like to deride as "not doing it right the first time", is a key part of the design process. (Teams that don't refactor all the time are usually in big trouble -- and then unhappy with the other agile practices they have adopted.)

As with any idea that becomes more buzzword than idea, there is always a huge risk that the energy of the "movement" will flame out early when things don't go as predicted by eager creators and early adopters. We see the same thing happen in educational settings all the time. Many of you have lived through objects-first in the CS curriculum.

Software patterns encountered the same fate. Hype outran practice. When this happens, it is usually best to let the fad die out. The good news is that some people will persevere with the good part of the idea and do wonderful things. The most recent patterns example I know of is the resurgence of interest in patterns in the parallel programming community, which faces many of the same challenges that faced a world moving to object-oriented programming faced fifteen years ago. The Parallel Computing Laboratory at Cal-Berkeley is undertaking an ambitious pattern language project in this area.

Echoing Shore:

What frustrates me the most is that this situation is entirely avoidable. In a green-field environment, the solid agile engineering practices included in Extreme Programming pay for themselves within the first few months.

When this passage leads the person with whom you are speaking to say,

I didn't know anyone used XP anymore. I feel sorry for them.

... you'll know it's time to stop talking. The religion that is getting in the way of developing software better may not be on the agile side of the conversation.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

November 22, 2008 7:19 AM

Code, and Lots Of It

Today, I was asked the best question ever by a high-school student.

During the fall, we host weekly campus visits by prospective students who are interested in majoring in CS. Most are accompanied by their parents, and most of the dialogue in the sessions is driven by the parents. Today's visitors were buddies from school who attended sans parents. As a part of our talking about careers open to CS grads, I mentioned that some grads like to move into positions where they don't deal much with code. I told them that two of the things I don't like about my current position is that I only get to teach one course each semester and that I don't have much time to cut code. Off-handedly, I said, "I'm a programmer."

Without missing a beat, one the students asked me, "What hobby projects are you working on?"

Score! I talked about a couple of things I work on whenever I can, little utilities I'm growing for myself in Ruby and Scheme, and some refactoring support for myself in Scheme. But the question was much more important than the answer.

Some people like to program. Sometimes we discover the passion in unexpected ways, as we saw in the article I referred to in my recent entry:

[Leah] Culver started out as an art major at the University of Minnesota, but found her calling in a required programming class. "Before that I didn't even know what programming was," she admits. ... She built Pownce from scratch using a programming language called Python.

Programmers find a way to program, just as runners find a way to run. I must admit, though, that I am in awe of the numbers Steve Yegge uses when talking about all the code he has written when you take into account his professional and personal projects:

I've now written at least 30,000 lines of serious code in both Emacs Lisp and JavaScript, which pales next to the 750,000 or so lines of Java I've [spit] out, and doesn't even compare to the amount of C, Python, assembly language or other stuff I've written.

Wow. I'll have to do a back-of-the-envelope estimate of my total output sometime... In any case, I am willing to stipulate to his claim that:

... 30,000 lines is a pretty good hunk of code for getting to know a language. Especially if you're writing an interpreter for one language in another language: you wind up knowing both better than you ever wanted to know them.

The students in our compiler course will get a small taste of this next semester, though even I -- with the reputation of a slave driver -- can't expect them to produce 30 KLOC in a single project! I can assure them that they will make a non-trivial dent in the 10,000 hours of practice they need to master their discipline. And most will be glad for it.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

November 20, 2008 8:22 PM

Agile Thoughts: Humans Plus Code

Courtesy of Brian Marick and his Agile Development Practices keynote:

Humans plus running code are smarter than humans plus time.

We can sit around all day thinking, and we may come up with something good. But if we turn our thoughts into code and execute it, we will probably get there faster. Running a piece of code gives us information, and we can use that feedback to work smarter. Besides, the act of writing the code itself tends to make us smarter, because writing code forces us to be honest with ourselves in places where abstract thought can get away with being sloppy.

Brian offers this assertion as an assumption that underlies the agile software value of working software, and specifically as assumption that underlies a guideline he learned from Kent Beck:

No design discussion should last more than 15 minutes without someone turning to a computer to do an experiment.

An experiment gives us facts, and facts have a way of shutting down the paths to fruitless (and often strenuous) argument we all love to follow whenever we don't have facts.

I love Kent Beck. He has a way of capturing great ideas in simple aphorisms that focus my mind. Don't make the mistake that some people make, trying to turn one of his aphorisms into more than it is. This isn't a hard and fast rule, and it probably does not apply in every context. But it does capture an idea that many of us in software development share: execucting a real program usually gives us answers faster and more reliably than a bunch of software developers sitting around pontificating about a theoretical program.

As Brian says:

Rather than spending too much time predicting the future, you take a stab at it and react to what you learn from writing and running code...

This makes for a nice play on Alan Kay's most famous bon mot, "The best way to predict the future is to invent it." The best way to predict the future of a program is to invent it: to write the program, and to see how it works. Agile software development depends on the fact that software is -- or should be -- soft, malleable, workable in our hands. Invent the future of your program, knowing full well that you will get some things wrong, and use what you learn from writing and running the program to make it better. Pretty soon, you will know what the program should look like, because you will have it in hand.

To me, this is one of the best lessons from Brian's keynote, and well worth an Agile Thought.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

November 17, 2008 8:58 PM

Doing It Wrong Fast

Just this weekend I learned about Ashleigh Brilliant, a cartoonist and epigrammist. From little I've seen in a couple of days, his cartoons remind me of Hugh MacLeod's business-card doodles Gaping Void -- only with a 1930s graphic style and language that is more likely SFW.

This Brilliant cartoon, #3053, made it into my Agile Development Hall of Fame on first sight:

Doing it wrong fast... is at least better than doing it wrong slowly

Doing it wrong fast means that we have a chance to learn sooner, and so have a chance to be less wrong than yesterday.

This lesson was fresh in my mind over the weekend from a small dose of programming. I was working on the financial software I've decided to write for myself, which has me exploring a few corners of PLT Scheme that I don't use daily. As a result, I've been failing more frequently than usual. The best failures come rat-a-tat-tat, because they are often followed closely by an a-ha! Sunday, just before I learned of Brilliant's work, I felt one of those great releases when, for the first time, my code gave me an answer I did not already know and had not wanted to compute by hand: our family net worth. At that moment I was excited to verify the result manually (I'll need that test later!) and enjoy all the wrong wrong work that had brought me to this point. Brilliant has something.


Posted by Eugene Wallingford | Permalink | Categories: General, Software Development

October 20, 2008 7:31 PM

A Good Time to Be Agile

In recent weeks, the financial markets of the world have entered "interesting times". There is a great story to tell here about the role that computational models have played in the financial situation we face, but I have been more intrigued by another connection to computing, more specifically to software development. It turns out that these bad times for the economy are a good time to "be agile".

Paul Graham writes that this is a good time to start a start-up, in part because a start-up can be more nimble and consume fewer resources than a big software shop. A new product can grow in small steps in a market where resources are limited. Tim Bray expands on that idea in his post, A Good Time for Agility. It may be difficult to get major projects and corresponding big budgets approved in tough times, because most execs will be focused on cost containment and surviving to the quarterly report. But...

The classic Agile approach, where you pick two or three key features, spec'em out with test suites that involve the business side, build'em and test'em, and then think about maybe going back for the next two or three, well, that's starting to look awfully attractive.

Small steps and small up-front expense draw less attention than BDUF and multi-month budgets. And if they lead to concrete, measurable improvements, they have a greater chance of sticking. They might even lead to important new software.

The third example I read recently came in a posting to the XP mailing list, the link to which I seem to have lost. The gist was straightforward: The writer worked in the software arm of a major financial institution. Having previously adopted agile practices enabled his shop to shift direction on short notice in response to the market crash. They were not in the middle of a major project with a specific market but in the middle of ongoing creation of loan products. The market for their usual products deteriorated and were able to begin delivering software to a new market relatively quickly. This did not require a new major project, but a twist on their current trajectory.

This shouldn't surprise us. Agile approaches allow us to manage risk and change at finer levels of granularity, and in a time of major change the massive dinosaurs will be at a disadvantage against more nimble species.

Not all news is so rosy. Bureaucracy can still dominate an environment. Last Friday, an alumnus of our department gave a talk for our current students on how not to stink in industry. His advice was uniformly practical, with many of his technical points reminiscent of The Practical Programmer. But in response to a question about XP and agile practices, his comments were not so positive. He and his team have not yet figured out how to do planning for XP projects, so they are left with tool-specific XP practices such as pair programming and testing early and often. I think that I can help him get a grip on XP-style planning, and offered to do so, but I think his problem goes deeper, to something he has little control over: his team's customers expect big project plans and fixed-price "contracts".

This is not a new problem. I was fortunate to visit RoleModel Software back when Ken Auer was first building it, and one topic of discussion within the company was how to educate clients about a new way of planning and budgeting for projects and how to shift the culture when all of its competitors was doing the same old thing. His potential customers had one way of managing the risk they faced, and that was do to things the usual way, even if that led to software that was off target, over budget, and over time. I don't know much more about the issue than this and need to see if anyone has written of positive experiences with it in industry.

My former student works for a government agency, which perhaps makes the bureaucracy hard to move by law or administrative rule, rather than by market forces. I feel for him as my department continues to work on outcomes assessment. University mandates are my job's version of "the customer demands a big project plan". (Outcomes assessment is an academic form of unit testing for its curriculum.) As we try to enact an outcomes assessment plan in small steps, we face a requirement to produce a BDUF plan by the end of this year. It's hard to figure out what will work best for us if we have to predict what is best up front. Some will tell us that the academic world understands outcomes assessment well enough to design a suitable plan from scratch, but many of us in the trenches will disagree. It's certainly possible to design from scratch a plan that looks familiar to other people, but who knows if that is what will help this department and this faculty steer its programs most effectively?

Complete operational plans of this sort often end up being as useful as many of their software design counterparts. Worse, mandates for such also tend to counterproductive, because when the last big plan fails, and when administration doesn't follow through by holding departments accountable for fixing the plans, faculty learn to mistrust both the mandates and the plans. That is how the link in the previous paragraph can be to a post nearly two years old, yet my department still not have an effective assessment plan in place: the faculty have a hard time justifying spending the time and energy to take on such a big project if it is likely to fail or if not developing a plan has no consequences.

I am hoping that we can use the most recent mandate as an opportunity to begin growing an assessment regimen that will serve us well over time. I believe in units tests and continuous feedback. I'm also willing to argue to the administration that an "incomplete" but implementable plan is better than a complete plan with no follow-through.

As the software guys are saying, this is a good time to be agile.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

October 02, 2008 7:12 PM

The Opposite of "Don't Do That"

I had one of those agile moments on Wednesday. A colleague stopped by my office to share his good feeling. He had just come from a CS 2 lab. "I love it whenever I design a lab in which students work in pairs. There is such life in the lab!" He went on to explain the interactions within pairs but also across pairs; one group would hear what another was thinking or doing, and would ask about it. So much learning was in the air.

This reminded me of the old joke... Patient: "Doctor, it hurts when I do this." (Demonstrates.) "Can you help me?" Doctor: "Sure. Don't do that."

Of course, it reminded of the negative space around the joke. Patient: "Doctor, life is great when I do this." (Demonstrates.) "Can you help me?" Doctor: "Sure. Do more of that."

"But..." But. We faculty are creatures of habit, both in knowing and in doing. We just know we can't teach all of our material with students working in pairs, so we don't. I think we can, even when I don't follow my own advice. (Doctor, heal thyself!) We design the labs, so if we want students to work in pairs, we can have them work in pairs.

I've had one or two successful experiences with all pair programming all the time in closed labs. Back when we taught CS1 and CS2 in C++, in the mid-1990s, and I was doing our first-year courses a lot, I designed all of my labs for students working in pairs. I wish I could say I had bee visionary, but my motivation was extrinsic: I had 25-30 students in class and 15 computers in the lab. Students worked with different students every week, in pseudo-random assignments of my device.

My C++-based courses probably weren't very good -- I was relatively new to teaching, and we were using C++ after all -- and the paired programming in our lab sessions may have been one of the saving graces: students shared their perplexity and helped each other learn. When they worked on outside programming assignments for the course, they could call on a sturdy network of friends they had built in lab sessions. Without the pairs, I fear that our course would have worked well for very few students.

If something works well, let's try to understand the context in which it works, and then do it more often in those contexts. That's an agile sentiment, whether we apply it to pair programming or not. Whether we apply it at the university or in industry. Whether we apply it to software development or any other practice in which we find ourselves engaged.


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

September 29, 2008 4:22 PM

Programming, Pictures, and Code

When I first came to UNI, a colleague and I talked a lot about programming by novices, graphical programming, programming by example, declarative programming, and the like. Many people saw ideas such as these as a way to broaden participation by making it possible for people to program without "programming". Anyone can draw a flowchart, right? Or program by dragging and dropping widgets, right?

No, said my colleague. He was fond of saying that all of those solutions were really just new kinds of programming language in disguise; ultimately, you had to know how to write a program. That may not be an insanely difficult task, but it is not a trivial task, either -- even if pictures were the lingua franca.

Yet the world goes on, looking for its next way to bypass the hard work of programming and make it disappear with pretty pictures. So I'm glad when people say out loud in public what my colleague has always said in-house. Here is Uncle Bob Martin sounding in on the latest, model-driven architecture:

Some folks have put a great deal of hope in technologies like MDA. I don't. The reason is that I don't see MDA as anything more than a different kind of computer language. To be effective it will still need 'if' and 'for' statements of some kind. And 'programmers' will still need to write programs in that language, because details will still need to be managed. There is no language that can eliminate the programming step, because the programming step is the translation from requirements to systems irrespective of language. MDA does not change this.

Programming is the translation from requirements to systems, whether we write it down in C, Java, or Ruby -- or an MDA model. There will be always be a program, and so there will be always be programmers. Making better programming tools helps, but as Bob says we also need thinkers, practitioners and academics alike, to figure out better what it means "to program" and to help others learn how to do it.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

September 26, 2008 5:24 AM

An Experiment with Students Creating Examples

A couple of weeks ago, I mentioned that I might have my students create their own examples for a homework assignment. Among the possible benefits of this were:

  • helping the programmers to write down their understanding of the problem in a concrete way early in the process
  • giving the programmers a way of to ask concrete questions early in the process -- and reason to ask the questions
  • helping the programmers know how much code to write and when to stop

I tried this and, as usual, learned as much or more than my students.

Getting students to think concretely about their tasks is tough, but asking them to write examples seemed to help. Most of them made a pretty good effort and so fleshed out what the one- or two-line text description I gave them meant. I saw lots of the normal cases for each task but also examples at the boundaries of the spec (What if the list is empty?) and on the types of arguments (What if the user passes an integer when the procedure asks for a list? What if the user passes -1 when the procedure expects a non-negative integer?) In class, before the assignment was due, we were able to discuss how much type checking we want our procedures to do, if any, in a language like Scheme without manifest types. Similarly, should we write examples with the wrong number of arguments, which result in an error?

I noticed that most students' examples contrasted cases with different inputs to a procedure, but that few thought about different kinds of output from the procedure. Can filter return an empty list? Well, sure; can you show me an example? I'll know next time to talk to students about this and have them think more broadly about their specs.

Requiring examples part-way through the assignment did motivate questions earlier than usual. On previous assignments, if I received any questions at all, they tended to arrive in my mailbox the night before the programs were due. That was still the case, but now the deadline was halfway through the assignment period, before they had written any code. And most of the class seemed happy to comply with my request that they write their examples before they wrote their code. (They are rarely in a hurry to write their code!)

Did having their own examples in hand help the students know how much code to write and when to stop? Would examples provided by me have helped as much? I don't know, but I guess 'yes' to both. Hmm. I didn't ask students about this! Next time...

Seeing their examples early helped me as much writing their examples early helped them. They got valuable feedback, yes, but so did I. I learned a bit of what they were thinking about the specific problems at hand, but I also learned a bit of what they think about more generally when faced with a programming task.

My first attempt at this also gave me some insight about how to describe the idea of writing examples better, and why it's worth the effort. The examples should clarify the textual description of the problem. They aren't about testing. They may be useful as tests later, but they probably aren't sufficient. (They approximate are a form of black box testing, but not white box testing.) As clarifiers, one might take an extreme position: If the textual description of the problem were missing, would the examples be enough for us to know what procedure to write? At this extreme, examples with the wrong number and type of arguments might be essential; in the more conventional role of clarifying the spec, those examples are unnecessary.

One thing that intrigued me after I made this assignment is that students might use their examples as the source material for test-driven development. (There's that word again.) I doubt many students consider this on their own; a few have an inclination to write and test code in close temporal proximity, but TDD isn't a natural outgrowth of that for most of them. In any case, we are currently learning a pattern-driven style of programming, so they have a pretty good idea of what their simplest piece of code will look like. There is a nice connection, though. Structural recursion relies on mimicking the structure of the input data, and that data definition also gives the programmer an idea about the kinds of input for which she should have examples. That s-list is either an empty list or a pair...

I'm probably reinventing a lot of wheels that the crew behind How to Design Programs smoothed out long ago. But I feel like I'm learning something useful along the way.


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

September 23, 2008 6:47 AM

From a Champion's Mind

I'm a big tennis fan. I like to play and would love to play more, though I've never played well. But I also like to watch tennis -- it is a game of athleticism and strategy. The players are often colorful, yet many of the greatest have been quiet, classy, and respectful of the game. I confess a penchant for the colorful players; Jimmy Connors is my favorite player of all time, and in the 1990s my favorite was Andre Agassi.

Agassi's chief rival throughout his career was one of the game's all-time greats, Pete Sampras. Sampras won a record fourteen Grand Slam titles (a record under assault by the remarkable Roger Federer) and finished six consecutive years as the top-ranked player in the world (a record that no one is likely to break any time soon). He was also one of the quiet, respectful players, much more like me than the loud Agassi, who early in his career seemed to thrive on challenging authority and crossing boundaries just for the attention.

Sampras recently published a tennis memoir, A Champion's Mind, which I gladly read -- a rare treat these days, reading a book purely for pleasure. But even while reading for pleasure I could not help noticing parallels to my professional interest in software development and teaching. I saw in Sampras's experience some lessons that that we in CS have also learned. Here are a few.

Teaching and Humility

After Sampras had made his mark as a great player, one of his first coaches liked to be known as one of the coaches who helped make Sampras the player he was. Sampras gave that coach his due, and gave the two men who coached him for most of his pro career a huge amount of credit for honing specific elements of his game and strategy. But without sounding arrogant, he also was clear that no coach "made" him. He had a certain amount of native talent, and he was also born with the kind of personality that drove him to excel. Sampras would likely have been one of the all-time greats even if he had had different coaches in his youth, and even as a pro.

Great performers have what it takes to succeed. It is rare for a teacher to help create greatness in a student. What made Sampras's pro coaches so great themselves is not that they built Sampras but that they were able to identify the one or two things that he needed at that point in his career and helped him work on those parts of his game -- or his mind. Otherwise, they let the drive within him push him forward.

As a teacher, I try figure out what students need and help them find that. It's tough to do when teaching a class of twenty-five students, because so much of the teaching is done with the group and so cannot be tailored to the individual as much as I might like and as much as each might need. But when mentoring students, whether grad students or undergrads, a dose of humility is in order. As I think back to the very best of my past students, I realize that I was most successful when I helped them get past roadblocks or to remove some source of friction in their thinking or their doing. Their energy often energized me, and I fed off of the relationship as much as they did.

Agile Moments

The secret of greatness is working hard day in and day out. Sampras grew as a player because he had to in order to achieve his goal of finishing six straight years as #1. And the only way to do that was to add value to his game every day. This seems consistent with agile developers' emphasis on adding value to their programs every day, through small steps and daily builds. Being out there every day also makes it possible to get feedback more frequently and so make the next day's work potentially more valuable. For some reason, Sampras's comments on a commitment to being in the arena day in and day out reminded me of one of Kent Beck's early bits of writing on XP, in which he proclaimed that, and the end of the day, if you hadn't produced some code, you probably had not given your customer any value. I think Sampras felt similarly.

Finally, this paragraph from a man who never changed the model of racket he used throughout his career, even as technology made it possible for lesser players to serve bigger and hit more powerful ground strokes. Here he speaks of the court on which his legend grew beyond ordinary proportion, Centre Court at the All England Club:

I enjoyed the relative "softness" of the court; it was terrific to feel the sod give gently beneath my feet with every step. I felt catlike out there, like I was on a soft play mat where I could do as I pleased without worry, fear, or excessive wear and tear. Centre Court always made me feel connected to my craft, and the sophisticated British crowd enhanced that feeling. It was a pleasure to play before them, and they inspired me to play my best. Wimbledon is a shrine, and it was always a joy to perform there.

Whatever else the agile crowd is about, feeling connected to the craft of making software is at its heart. I like to use tools that give gently beneath my feet, that let me make progress without worry and fear. Even ordinary craftsmen such as I appreciate these feelings.


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

September 19, 2008 5:12 PM

Design Creates People, Not Things

The latest issue of ACM's on-line pub Ubiquity consists of Chauncey Bell's My Problem with Design, an article that first appeared on his blog a year ago. I almost stopped reading it early on, distracted by other things and not enamored with its wordiness. (I'm one to talk about another writer's wordiness!) I'm glad I read the whole article, because Bell has an inspiring take on design for a world that has redefined the word from its classic sense. He echoes a common theme of the software patterns and software craftsmanship crowd, that in separating design from the other tasks involved in making an artifact we diminish the concept of design, and ultimately we diminish the quality of the artifact thus made.

But I was especially struck by these words:

The distinctive character of the designer shapes each design that affects us, and at the same time the designer is shaped by his/her inventions. Successful designs shape those for whom they are designed. The designs alter people's worlds, how they understand those worlds, and the character and possibilities of inhabiting those worlds. ...

Most of our contemporaries tell a different story about designing, in which designers fashion or craft artifacts (including "information") that others "use." One reason that we talk about it this way, I think, is that it can be frightening to contemplate the actual consequences of our actions. Do we dare speak a story in which, in the process of designing structures in which others live, we are designing them, their possibilities, what they attend to, the choices they will make, and so forth?

(The passage I clipped gives the networked computer as the signature example of our era.)

Successful designs shape those for whom they are designed. In designing structures for people, we design them, their possibilities.

I wonder how often we who make software think this sobering thought. How often do we simply string characters together without considering that our product might -- should?! -- change the lives of its users? My experience with software written by small, independent developers for the Mac leads me to think that at least a few programmers believe they are doing something more than "just" cutting code to make a buck.

I have had similar feelings about tools built for the agile world. Even if Ward and Kent were only scratching their own itches when they built their first unit-testing framework in Smalltalk, something tells me they knew they were doing more than "making a tool"; they were changing how they could write Smalltalk. And I believe that Kent and Erich knew that JUnit would redefine the world of the developers who adopted it.

What about educators? I wonder how often we who "design curriculum" think this sobering thought. Our students should become new people after taking even one of our courses. If they don't, then the course wasn't part of their education; it's just a line on their transcripts. How sad. After four years in a degree programs, our students should see and want possibilities that were beyond their ken at the start.

I've been fortunate in my years to come to know many CS educators for whom designing curriculum is more than writing a syllabus and showing up 40 times in a semester. Most educators care much more than that, of course, or they would probably be in industry. (Just showing up out there pays better than just showing up around here, if you can hold the gig.) But even if we care, do we really think all the time about how our courses are creating people, not just degree programs? And even if we think this way in some abstract way, how often do we let it seep down into our daily actions. That's tough. A lot of us are trying.

I know there's nothing new here. Way back, I wrote another entry on the riff that "design, well done, satisfies needs users didn't know they had". Yet it's probably worth reminding ourselves about this every so often, and to keep in mind that what we are doing today, right now, is probably a form of design. Whose world and possibilities are we defining?

This thought fits nicely with another theme among some CS educators these days, context. We should design in context: in the context of implementation and the other acts inherent in making something, yes, but also in the context of our ultimate community of users. Educators such as Owen Astrachan are trying help us think about our computing in the context of problems that matter to people outside of the CS building. Others, such as Mark Guzdial, have been preaching computing in context for a while now. I write occasionally on this topic here. If we think about the context of our students, as we will if we think of design as shaping people, then putting our courses and curricula into context becomes the natural next step.


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

September 12, 2008 5:43 PM

Creating Examples and Writing Programs

On the PLT Scheme mailing list, someone asked why the authors of How to Design Programs do not provide unit tests for their exercises. The questioner could understand not giving solutions, but why not give the examples that the students could use to guide their thinking. A list member who is not an HtDP c-author speculated that if the authors provided unit tests then students would not bother to implement their own.

Co-author Matthias Felleisen responded "Yes" and added this stronger assertion:

I have come to believe that being able to make up your own examples (inputs, outputs) is the critical step in solving most problems.

Writing examples is one of the essential elements of the "design recipe" approach on which Felleisen et al. base How to Design Programs. The idea itself isn't new, as I'm sure the book's authors will tell you. Some CS teachers have been requiring students to write test cases or test plans for many years, and the practice is similar to what some engineers learn to do from the start of their education. Heck, test-driven design has gone from being the latest rage in agile development to an accepted (if too infrequently practiced) part of creating software.

What HtDP and TDD do is to remind us all of the importance of the practice and to make it an essential step in the student's or developer's programming process.

What struck me by Matthias's response is that making up examples is the critical step in writing code. It is certainly reasonable, for so many reasons, among them:

  • It forces the programmer to write down her understanding of the problem in a concrete way early in the process. Concrete understanding is always preferable to the fuzzy-minded understanding that follows reading a problem statement. Besides, writing a program requires that level of understanding.

  • Having examples in hand gives the programmer a way of talking to the client or teacher to see if her understanding matches that of the person who "owns" the problem.

  • It gives the programmer a way of knowing how much code to write and so when to stop. Most students can use that guidance.

I usually give my students several examples as a part of specifying problems and ask them to write a few of their own. Most don't do much on their own and, uncharacteristically, I don't hold them accountable often enough. My next programming assignment may look different from the previous ones; I have an idea of how to sneak this little bit of design recipe thinking into the process.


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

September 10, 2008 2:59 PM

"Yes, We Do That"

When I was in grad school, my advisor sent me to a series of swank conferences on expert systems in business, finance, and accounting. Among the things these conferences did for me was to give a chance to stay at Ritz Carlton hotels. This Midwestern boy had never been treated so well.

At the 1990 conference, I heard a talk by Gary Ribar from KPMG Peat Marwick, one of the Big Six accounting consulting firms of the time. Ribar described LoanProbe, a program that evaluated the collectibility of commercial loans. LoanProbe was a rule-based system organized in a peculiar way, with its 9000 rules separated into thirty-three separate "knowledge bases". It was a significant application that interacted with sixty external programs and two large data bases. Peat Marwick took LoanProbe a step further and used its organizational technique to build a knowledge acquisition program that enabled non-programmers to create systems with a similar structure.

I was so excited. I recognized this technique as what we in our lab called structured matching, a remarkably common and versatile pattern in knowledge-based systems. LoanProbe looked to me like the largest documented application of structured matching, which I was working on as a part of my research. Naturally, I wanted to make a connection to this work and share experiences with the speaker.

After the talk, I waited in line to speak with him. When my turn came, I gushed that their generic architecture was very cool and that "we do something just like that in our lab!". I expected camaraderie, but all I received back was an icy stare, a curt response, and an end to the conversation.

I didn't understand. Call me naive. For a while, I wondered if Mr. Ribar was simply an unfriendly guy. Then I realized that he probably took my comment not as a compliment -- We do that, too! -- but as a claim that the work he described was less valuable because it was not novel. I realized that I had violated one of the basic courtesies of research by telling him that his work was known already.

These days, I think fondly of Ribar, that talk, and that conference. He was behaving perfectly reasonably, given the culture in which he worked. Novelty is prized.

A few years after that conference, I came across PLoP and the software patterns community. This group of people valued discovering, documenting, and sharing common solutions, the patterns that make our software and our programming lives better. Structured Matcher did that, and it appeared in programs from all sorts of domain.

Jeff Patton has described this feature of the patterns community nicely in his article on emerging best practices in user experience:

If you tell someone a great idea, and they say "Yes, we do something like that too!", that's a pattern.

Documenting and sharing old, proven solutions that expert practitioners use may not get you a publication in the best research journal (though it might, if you are persistent and fortunate), but it will make the world better for programmers and software users. That is valuable, too.


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

August 15, 2008 2:35 PM

Less, Sooner

Fall semester is just around the corner. Students will begin to arrive on campus next week, and classes start a week from Monday. I haven't been able to spend much time on my class yet and am looking forward to next week, when I can.

What I have been doing is clearing a backlog of to-dos from the summer and handling standing tasks that come with the start of a new semester and especially a new academic year. This means managing several different to-do lists, crossing priorities, and generally trying to get things done.

As I look at this mound of things to do I can't help being reminded of something Jeff Patton blogged a month or so ago: two secrets of success in software development, courtesy of agile methods pioneer Jim Highsmith: start sooner, and do less.

Time ain't some magical quantity that I can conjure out of the air. It is finite, fixed, and flowing relentlessly by. If I can't seem to get done on time, I need to start sooner. If I can't seem to get it all done, I need to do less. Nifty procedures and good tools can help only so much.

I need to keep this in mind every day of the year.

Oh, and to you students out there: You may not be able to do less work in my class, but you can start sooner. You may have said so yourself at the end of last semester. Heck, you may even want to do more, like read the book...


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

August 12, 2008 4:24 PM

TDD and GTD: Instances of a Pattern

I once wrote that extreme programming is a self-help system. This generalizes pretty well to other software methodologies, too. As we step away from developing software to personal hygiene, there is an entire ecosystem around the notion of life hacks, self-help for managing information and combatting data overload. Programmers and techies are active players in the lifehacking community because, well, we love to make tools to solve our problems and we love self-help systems. In the end, sometimes, we spend more time making tools and playing with them than actually solving our problems.

One of the popular lifehacking systems among techies is David Allen's Getting Things Done, or GTD. I've never read the book or adopted the system, but I've read about it and borrowed some of its practices in trying to treat my own case of information overload. The practices I have borrowed feel a lot like XP and especially test-driven development. Maybe that's why they appeal to me.

Consider this post on the basic concepts of GTD. Here is why GTD makes me think of TDD:

  1. think in terms of outcomes: write a test
  2. take the next action: take a simple action
  3. review your circumstances regularly: refactor

This is not a perfect match. In GTD, a goal from Step 1 may require many next actions, executed in sequence. In TDD, we decompose such big goals into smaller steps so that we can define a very clear next action to perform. And in GTD, Step 3 isn't really refactoring of a system. It's more a global check of where you are and how your lists of projects and next actions need to be revised or pruned. What resonates, though, is its discipline of regular review of where you are headed and how well your current 'design' can get you there.

It's not a perfect match, but then no metaphor is. Yet the vibe feels undeniably similar to me. Each has a mindset of short-term accountability through tests, small steps to achieve simple, clear goals, and regular review and clean-up of the system. The lifehackers who play with GTD even like to build tools to automate as much as they can so that they stay in the flow of getting things done as much as possible and trust their tools to help them manage performance and progress.

Successful patterns recur. I shouldn't be surprised to find these similarities.


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

August 11, 2008 2:38 PM

Side Effects and Types in Refactoring

Greg Wilson relates an observation by Michael Feathers: "refactoring pure functional code is a lot easier than refactoring imperative code". In one sense, this ought not to surprise us. When we eliminate side effects from our code, dependencies among functions flow through parameters, which make individual functions more predictably independent of one another. Without side effects, we don't have sequences of statements, which encourages smaller functions, which also makes it easier to understand the functions.

(A function call does involve sequencing, because arguments are evaluated before the function is invoked. But this encourages small functions, too: Deeply-nested expressions can be quite hard to read.)

There is another force counteracting this one, though. Feathers has been playing a lot with Haskell, which is strongly-typed through manifest types and type inferencing. Many functional languages are dynamically-typed, and dynamic typing makes it harder to refactor functional programs -- at least to guarantee that a particular refactoring does not change the program's behavior.

I'm a Scheme programmer when I use a functional language, so I encounter the conflict between these two forces. My suspicion from personal experience is that functional programmers need less support, or at least different kinds of support, when it comes to refactoring tools. The first key step is to identify refactorings from FP practice. From there, we can find ways to automate support for these refactorings. This is a longstanding interest of mine. One downside to my current position is a lack of time to devote to this research project...


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

August 07, 2008 2:57 PM

Design Ideas Lying in Wait

Ralph Johnson pointed me to a design idea for very large databases called a shard. This is a neat little essay for several reasons. First, its author, Todd Hoff, explains an architecture for massive, distributed databases that has grown up in support of several well-known, high-performance web sites, including Flickr, Google, and LiveJournal. Second, Hoff also wrote articles that describe the architectures of Flickr, Google, and LiveJournal. Third, all four pages point to external articles that are the source of the information summarized. Collectively, these pages make a wonderful text on building scalable data-based web systems.

I've posted this entry in my Patterns category because this recurring architecture has all the hallmarks of a design pattern. It even has great name and satisfies Rule Of Three, something I've mentioned before -- and what a fine three it is. Each implementation uses the idea of a shard slightly differently, in fitting with the particular forces at play in the three companies' systems.

Buried near the bullet list on the Google page was an item worth repeating:

Don't ignore the Academy. Academia has a lot of good ideas that don't get translated into production environments. Most of what Google has done has prior art, just not prior large scale deployment.

This advice is a bit different from some advice I once shared for entrepreneurs, looking for Unix commands that haven't been implemented on the web yet, but the spirit is similar. Sometimes I hear envious people remark that Google hasn't done anything special; they just used a bunch of ideas others created to build a big system. Now, I don't think that is strictly true, but I do think that many of the ideas they used existed before in the database and networking worlds. And to the extent that is true, good for them! They paid attention in school, read beyond their assignments, and found some cool ideas that they could try in practice. Isn't that the right thing to do?

In any case, I recommend this article and encourage others to write more like it.


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

July 31, 2008 12:12 PM

Small Programs and Limited Language

A recent entry mentioned that one advantage of short source code for beginners is a smaller space for errors. If a student writes only three lines of code, then any error in the program is probably on one of those three lines. That's better than looking for errors in a 100-line program, at least when the programmer is learning.

This assertion may seem like an oversimplification. What if the students writes a bunch of three-line procedures that call one another? Couldn't an error arise out of the interaction of multiple procedures, and thus lie far from the point at which it is discovered? Sure, but that is usually only a problem if the student doesn't know that each three-line procedure works. If we develop the habit of testing each small piece of code well, or even reasoning formally about its behavior, then we can have confidence in the individual pieces, which focuses the search for an error in the short piece of code that calls them.

This is, of course, one of the motivations behind the agile practices of taking small steps and creating tests for each piece of code as we go along. It is also why programming in a scripting language can help novices. The language provides powerful constructs, which allow the novice programmer to say a lot in a small amount of code. We can trust the language constructs to work correctly, and so focus our search for errors in the small bit of code.

Even still, it's not always as simple as it sounds. I am reminded of an article on a new course proposed by Matthias Felleisen, in which he argues for the use of a limited proof language. Even when we think that a 'real' language is small enough to limit the scope of errors students can make, we are usually surprised. Felleisen comments on the Teach Scheme! experience:

... we used to give students the "simple language of first-order Lisp" and the code we saw was brutal. Students come up with the worst possible solution that you can imagine, even if you take this sentence into account in your predictions.

This led the Teach Scheme! team to create a sequence of language levels that expose students to increasingly richer sets of ideas and primitives, culminating in the complete language. This idea has also been in the Java world, via Dr. Java. Another benefit of using limited teaching languages is that the interpreter or compiler can provide much more specific feedback to students at each level because it, too, can take advantage of the smaller space of possible errors.

Felleisen does not limit the idea of limited language to the programming language. He writes of carefully introducing students to the vocabulary we use to talk about programming:

Freshmen are extremely limited in their vocabulary and "big words" (such as 'specification' and 'implementation') seem to intimidate them. We introduce them slowly and back off often.

When I read this a couple of weeks ago, it troubled me a bit. Not because I disagree with what Felleisen says, but because it seems to conflict with something else I believe and blogged about couple of weeks ago: speak to students in real language, and help the students grow into the language. I have had good experience with children, including my own, when talking about the world in natural language. What makes the experience of our students different.

As I write this, I am less concerned that these conflict. First, Felleisen mentions one feature of the CS1 experience that distinguishes it from my kids' experience growing up: fear. Children don't spend a lot of their time afraid of the world; they are curious and want to know more. They are knowledge sponges. CS1 students come out of a school system that tends to inculcate fear and dampen curiosity, and they tend to think computer science is a little scary -- despite wanting to major in it.

Second, when I speak to children in my usual vocabulary, I take the time to explain what words mean. Sometimes they ask, and sometimes I notice a quizzical curious look on their faces. Elaboration of ideas and words gives us more to talk about (a good thing) and connects to other parts of their knowledge (also good). And I'm sure that I don't speak to kids using only thirteen-letter words; that's not the nature of regular life, at least in my house. In computing jargon words of excessive length are the norm.

So I don't think there's a contradiction in these two ideas. Felleisen is reminding us to speak to students as if they are learners, which they are, and to use language carefully, not simplistically.

Even if there is a contradiction, I don't mind. It would not be the only contradiction I bear. Strange as it may sound, I try to be true to both of these ideas in my teaching. I try not to talk down to my students, instead talking to them about real problems and real solutions and cool ideas. My goal is to help students reach up to the vocabulary and ideas as they need, offering scaffolding in language and tools when they are helpful.


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

July 30, 2008 12:40 PM

Scripting, CS1, and Language Theory

Yesterday, I wrote a bit about scripting languages. It seems odd to have to talk about the value of scripting languages in 2008, as Ronald Loui does in his recent IEEE Computer article, but despite their omnipresence in industry, the academic world largely continues to prefer traditional systems languages. Some of us would like to see this change. First, let's consider the case of novice programmers.

Most scripting languages lack some of the features of systems languages that are considered important for learners, such as static typing. Yet these "safer" languages also get in the way of learning, as Loui writes, by imposing "enterprise-sized correctness" on the beginner.

Early programmers must learn to be creative and inventive, and they need programming tools that support exploration rather than production.

This kind of claim has been made for years by advocates of languages such as Scheme for CS1, but those languages were always dismissed by "practical" academics as toy languages or niche languages. Those people can't dismiss scripting languages so easily. You can call Python and Perl toy languages, but they are used widely in industry for significant tasks. The new ploy of these skeptics is to speak of the "scripting language du jour" and to dismiss them as fads that will disappear while real languages (read: C) remain.

What scripting language would be the best vehicle for CS1? Python has had the buzz in the CS ed community for a while. After having taught a little PHP las semester, I would deem it too haphazard for CS1. Sure, students should be able to do powerful things, but the pocket-protected academic in me prefers a language that at least pretends to embody good design principles, and the pragmatist in me prefers a language that offers a smoother transition into languages beyond scripting. JavaScript is an idea I've seen proposed more frequently of late, and it is a choice with some surprising positives. I don't have enough experience with it to say much, but I am a little concerned about the model that programming in a browser creates for beginning students.

Python and Ruby do seem like the best choices among the scripting languages with the widest and deepest reach. As Loui notes, few people dislike either, and most people respect both, to some level. Both have been designed carefully enough to be learned by beginners and and support a reasonable transition as students move to the next level of the curriculum. Having used both, I prefer Ruby, not only for its OO-ness but also for how free I feel when coding in it. But I certainly respect the attraction many people have to Python, especially for its better developed graphics support.

Some faculty ask whether scripting languages scale to enterprise-level software. My first reaction is: For teaching CS1, why should we care? Really? Students don't write enterprise-level software in CS1; they learn to program. Enabling creativity and supporting exploration are more important than the speed of the interpreter. If students are motivated, they will write code -- a lot of it. Practice makes perfect, not optimized loop unrolling and type hygiene.

My second reaction is that these languages scale quite nicely to real problems in industry. That is why they have been adopted so widely. If you need to process a large web access log, you really don't want to use Java, C, or Ada. You want Perl, Python, or Ruby. This level of scale gives us access to real problems in CS1, and for these tasks scripting languages do more than well enough. Add to that their simplicity and the ability to do a lot with a little code, and student learning is enhanced.

Loui writes, "Indeed, scripting languages are not the answer for long-lasting, CPU-intensive nested loops." But then, Java and C++ and Ada aren't the answer for all the code we write, either. Many of the daily tasks that programmers perform lie in the space better covered by scripting languages. After learning a simpler language that is useful for these daily tasks, students can move on to larger-scale problems and learn the role of a larger-scale language in solving them. That seems more natural to me than going in the other direction.

Now let's consider the case of academic programming languages research. A lot of interesting work is being done in industry on the design and implementation of scripting language, but Loui laments that academic PL research still focus on syntactic and semantic issues of more traditional languages.

Actually, I see a lot of academic work on DSLs -- domain-specific languages -- that is of value. One problem is this research is so theoretical that it is beyond the interest of programmers in the trenches. Then again, it's beyond the mathematical ability and interest of many CS academics, too. (I recently had to comfort a tech entrepreneur friend of mine who was distraught that he couldn't understand even the titles of some PL theory papers on the resume of a programmer he was thinking of hiring. I told him that the lambda calculus does that to people!)

Loui suggest that PL language research might profitably move in a direction taken by linguistics and consider pragmatics rather than syntax and semantics. Instead of proving something more about type systems, perhaps a languages researcher might consider "the disruptive influence that Ruby on Rails might have on web programming". Studying how well "convention over configuration" works in practice might be of as much use as incrementally extending a compiler optimization technique. The effect of pragmatics research would further blur the line between programming languages and software engineering, a line we have seen crossed by some academics from the PLT Scheme community. This has turned out to be practical for PL academics who are interested in tools that support the programming process.

Loui's discussion of programming pragmatics reminds me of my time in studying knowledge-based systems. Our work was pragmatic, in the sense that we sought to model the algorithms and data organization that expert problem solvers used, which we found to be tailored to specific problem types. Other researchers working on such task-specific architectures arrived at models consistent with ours. One particular group went beyond modeling cognitive structures to the sociology of problem solving, John McDermott's lab at Carnegie Mellon. I was impressed by McDermott's focus on understanding problem solvers in an almost anthropological way, but at the time I was hopelessly in love with the algorithm and language side of things to incorporate this kind of observation into my own work. Now, I recognize it as the pragmatics side of knowledge-based systems.

(McDermott was well known in the expert systems community for his work on the pioneering programs R1 and XCON. I googled him to find out what he was up to these days but didn't find much, but through some publications, I infer that he must now be with the Center for High Assurance Computer Systems at the Naval Research Laboratory. I guess that accounts for the sparse web presence.)

Reading Loui's article was an enjoyable repast, though even he admits that much of the piece reflects old arguments from proponents of dynamic languages. It did have, I think, at least one fact off track. He asserts that Java displaced Scheme as the primary language used in CS1. If that is true, it is so only for a slender subset of more elite schools, or perhaps that Scheme made inroads during a brief interregnum between Java and ... Pascal, a traditional procedural language that was small and simple enough to mostly stay out of the way of programmers and learners.

As with so many current papers, one of the best results of reading it is a reminder of a piece of classic literature, in this case Ousterhout's 1998 essay. I usually read this paper again each time I teach programming languages, and with my next offering of that course to begin in three weeks, the timing is perfect to read it again.


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

July 29, 2008 2:03 PM

Scripting Languages, Software Development, and Novice Programmers

Colleague and reader Michael Berman pointed me to the July 2008 issue of IEEE Computer, which includes an article on the virtues of scripting languages, Ronald Loui's In Praise of Scripting: Real Programming Pragmatism. Loui's inspiration is an even more important article in praise of scripting, John Ousterhout's classic Scripting: Higher Level Programming for the 21st Century. Both papers tell us that scripting deserves more respect in the hierarchy of programming and that scripting languages deserve more consideration in the programming language and CS education communities.

New programming languages come from many sources, but most are created to fill some niche. Sometimes the niche is theoretical, but more often the creators want to be able to do something more easily than they can with existing languages. Scripting languages in particular tend to originate in practice, to fill a niche in the trenches, and grow from there. Sometimes, they come to be used just like a so-called general-purpose programming language.

When programmers have a problem that they need solve repeatedly, they want a language that gives them tools that are "ready at hand". For these programming tasks, power comes from the level of abstraction provided by built-in tools. Usually these tools are chosen to fill the needs of a specific niche, but they almost always include the ability to process text conveniently, quickly, and succinctly.

Succinctness is a special virtue of scripting languages. Loui mentions the virtue of short source code, and I'm surprised that more people don't talk about the value of small programs. Loui suggests one advantage that I rarely see discussed: languages that allow and even encourage short programs enable programmers to get done with a task before losing motivation or concentration. I don't know how important this advantage is for professional programmers; perhaps some of my readers who work in the real world can tell me what they think. I can say, though, that, when working with university students, and especially novice programmers, motivation or concentration are huge factors. I sometimes hear colleagues say that students who can't stay motivated and concentrate long enough to solve an assignment in C++, Ada, or Java probably should not be CS majors. This seems to ignore reality, both of human psychology and of past experience with students. Not to mention the fact that teach non-majors, too.

Another advantage of succinctness Loui proposes relates to programmer error. System-level languages include features intended to help programmers make fewer errors, such as static typing, naming schemes, and verbosity. But they also require programmers to spend more time writing code and to write more code, and in that time programmers find other ways to err. This is, too, is an interesting claim if applied to professional software development. One standard answer is that software development is not "just" programming and that such errors would disappear if we simply spent more time up-front in analysis, modeling, and design. Of course, these activities add even more time and more product to the lifecycle, and create more space for error. They also put farther in the future the developers' opportunity to get feedback from customers and users, which in many domains is the best way to eliminate the most important errors that can arise when making software.

Again, my experience is that students, especially CS1 students, find ways to make mistakes, regardless of how safe their language is.

One way to minimize errors and their effects is to shrink the universe of possible errors. Smaller programs -- less code -- is one way to do that. It's harder to make as many or even the same kind of errors in a small piece of code. It's also easier to find and fix errors in a small piece of code. There are exceptions to both of these assertions, but I think that they hold in most circumstances.

Students also have to be able to understand the problem they are trying to solve and the tools they are using to solve it. This places an upper bound on the abstraction level we can allow in the languages we give our novice students and the techniques we teach them. (This has long been an argument made by people who think we should not teach OO techniques in the first year, that they are too abstract for the minds of our typical first-year students.) All other things equal, concrete is good for beginning programmers -- and for learners of all kinds. The fact that scripting languages were designed for concrete tasks means that we are often able to make the connection for students between the languages abstractions and tasks they can appreciate, such as manipulating images, sound, and text.

My biases resonate with this claim in favor of scripting languages:

Students should learn to love their own possibilities before they learn to loathe other people's restrictions.

I've always applied this sentiment to languages such as Smalltalk and Scheme which, while not generally considered scripting languages, share many of the features that make scripting languages attractive.

In this regard, Java and Ada are the poster children in my department's early courses. Students in the C++ track don't suffer from this particular failing as much because they tend not to learn C++ anyway, but a more hygienic C. These students are more likely to lose motivation and concentration while drowning in an ocean of machine details.

When we consider the problem of teaching programming to beginners, this statement by Loui stands out as well:

Students who learn to script early are empowered throughout their college years, especially in the crucial Unix and Web environments.

Non-majors who want to learn a little programming to become more productive in their disciplines of choice don't get much value at all from one semester learning Java, Ada, or C++. (The one exception might be the physics majors, who do use C/C++ later.) But even majors benefit from learning a language that they might use sooner, say, in a summer job. A language like PHP, JavaScript, or even Perl is probably the most valuable in this regard. Java is the one "enterprise" language that many of our students can use in the summer jobs they tend to find, but unfortunately one or two semesters are not enough for most of them to master enough of the language to be able to contribute much in a professional environment.

Over the years, I have come to think that even more important than usefulness for summer jobs is the usefulness a language brings to students in their daily lives, and the mindset it fosters. I want CS students to customize their environments. I want them to automate the tasks they do every day when compiling programs and managing their files. I want them to automate their software testing.

When students learns a big, verbose, picky language, they come to think of writing a program as a major production, one that may well cause more pain in the short term than it relieves in the long term. Even if that is not true, the student looks at the near-term pain and may think, "No, thanks." When students learn a scripting language, they can see that writing a program should be as easy as having a good idea -- "I don't need to keep typing these same three commands over and over", or "A program can reorganize this data file for me." -- and writing it down. A program is an idea, made manifest in an executable form. They can make our lives better. Of all people, computer scientists should be able to harness their power -- even CS students.

This post has grown to cover much more than I had originally planned, and taken more time to write. I'll stop here for now and pick up this thread of thought in my next entry.


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

July 22, 2008 8:50 PM

Computing and Modern Culture

The recent rescue of hostages in Colombia relied on a strategy familiar to people interested in computer network security: a man-in-the-middle attack.

... for months, in an operation one army officer likened to a "broken telephone," military intelligence had been able to convince Ms. Betancourt's captor, Gerardo Aguilar, a guerrilla known as "Cesar," that he was communicating with his top bosses in the guerrillas' seven-man secretariat. Army intelligence convinced top guerrilla leaders that they were talking to Cesar. In reality, both were talking to army intelligence.

As Bruce Schneier reports in Wired magazine, this strategy is well-known on the internet, both to would-be system crackers and to security experts. The risk of man-in-the-middle attacks is heightened on-line because the primary safeguard against them -- shared social context -- is so often lacking. Schneier describes some of the technical methods available for reducing the risk of such attacks, but his tone is subdued... Even when people have a protection mechanism available, as they do in SSL, they usually don't take advantage of it. Why? Using the mechanism requires work, and most of us are just too lazy.

Then again, the probability of being victimized by a man-in-the-middle attack may be small enough that many of us can rationalize that the cost is greater than the benefit. That is a convenient thought, until we are victimized!

The problem feature that makes man-in-the-middle attacks possible is unjustified trust. This is not a feature of particular technical systems, but of any social system that relies on mediated communication. One of the neat things about the Colombian hostage story it that shows that some of the problems we study in computer science are relevant in a wider context, and that some of our technical solutions can be relevant, too. A little computer science can amplify the problem solving of almost anyone who deals with "systems", whatever their components.

This story shows a potential influence from computing on the wider world. Just so that you know the relationship runs both ways, I point you to Joshua Kerievsky's announcement of "Programming with the Stars", one of the events on the Developer Jam stage at the upcoming Agile 2008 conference. Programming with the Stars adapts the successful formula of Dancing with the Stars, a hit television show, to the world of programming. On the TV show, non-dancers of renown from other popular disciplines pair with professional dancers for a weekly dance competitions. Programming with the Stars will work similarly, only with (pair) programming plugged in for dancing. Rather than competitions involving samba or tango, the competitions will be in categories such as test-driven development of new code and refactoring a code base.

As in the show, each pair will include an expert and a non-expert, and there will be a panel of three judges:

I've already mentioned Uncle Bob in this blog, even in a humorous vein, and I envision him playing the role of Simon Cowell from "American Idol". How Davies and Hill compare to Paula Abdul and Randy Jackson, I don't know. But I expect plenty of sarcasm, gushing praise, and hip lingo from the panel, dog.

Computer scientists and software developers can draw inspiration from pop culture and have a little fun along the way. Just don't forget that the ideas we play with are real and serious. Ask those rescued hostages.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

July 10, 2008 1:54 PM

Object-Oriented Algorithm Flashback

Most papers presented at SIGCSE and the OOPSLA Educators' Symposium are about teaching methods, not computational methods. When the papers do contain new technical content, it's usually content that isn't really new, just new to the audience or to mainstream use in the classroom. The most prominent example of the latter that comes to mind immediately is the series of papers by Zung Nguyen and Stephen Wong at SIGCSE on design patterns for data structures. Those papers were valuable in principle because they showed that how one conceives of containers changes when one is working with objects. In practice, they sometimes missed their mark because they were so complex that many teachers in the audience said, "Cool! But I can't do that in class."

However, the OOPSLA Educators' Symposium this year received a submission with a cool object-oriented implementation of a common introductory programming topic. Unfortunately, it may not have made the cut for inclusion based on some technical concerns of the committee. Even so, I was so happy to see this paper and to play with the implementation a little on the side! It reminded me of one of the first efforts I saw in a mainstream CS book to show how we think differently about a problem we all know and love when working with objects. That was Tim Budd's implementation of the venerable eight queens problem in An Introduction to Object-Oriented Programming.

Rather than implement the typical procedural algorithm in an object-oriented language, Budd created a solution that allowed each queen to solve the problem for herself by doing some local computation and communicating with the queen to her right. I remember first studying his code to understand how it worked and then showing it to colleagues. Most of them just said, "Huh?" Changing how we think is hard, especially when we already have a perfectly satisfactory solution for the problem in mind. You have to want to get it, and then work until you do.

You can still find Budd's code from the "download area" link on the textbook's page, though you might find a more palatable version in the download area for the book's second edition. I just spent a few minutes creating a Ruby version, which you are welcome to. It is slightly Ruby-ized but mostly follows Budd's solution for now. (Note to self: have fun this weekend refactoring that code!)

Another thing I liked about "An Introduction to Object-Oriented Programming" was its linguistic ecumenism. All examples were given in four languages: Object Pascal, C++, Objective C, and Smalltalk. The reader could learn OOP without tying it to a single language, and Budd could point out subtle differences in how the languages worked. I was already a Smalltalk programmer and used this book as a way to learn some Objective C, a skill which has been useful again this decade.

(Budd's second edition was a step forward in one respect, by adding Java to the roster of languages. But it was also the beginning of the end. Java soon became so popular that the next version of his book used Java only. It was still a good book for its time, but it lost some of its value when it became monolingual.)


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

June 30, 2008 8:50 AM

The Other OOPSLA Submission

In March I talked about a couple of OOPSLA submissions written by our merged ChiliPLoP groups. In May I wrote about the verdict on one but forgot to mention the other. Maybe because the rejection was so much more interesting!

Anyone, our second submission was accepted into the Educators' Symposium. It is not a paper, really, but an extended abstract for an activity we will run: a code review recast as it might happen in a software studio. We hope to give participants a snapshot of what a studio-based course looks, feels, and works like. This is something instructors can try on a small scale in class and, if it works for them, expand throughout their course. Even if code reviews is all the farther they go, we co-authors think that this will be a useful step for many instructors. It draws on experiences in the writers' workshops of PLoP helps students to think about the many design choices they make when writing software, and to make them reflectively rather than subconsciously.

The real trick to this activity will be the homework we give before the symposium:

Before coming to OOPSLA, Educators' Symposium participants will be asked to submit a program, in a language of their choice (though using only standard libraries), which implements the core of a program to generate Tag Clouds from a data set. ...

My experience with many workshops in the past and especially with the Educators' Symposium is that participants never do this kind of homework. Some are well-intentioned but never make time for it, while others figure they can skate by without having written the code. (Sounds as if professors are a lot like their students, huh?) Without code to review, a code review doesn't get very far. We hope that we can find a way to encourage symposium attendees to overcome history and come with some code to workshop.


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

June 18, 2008 3:51 PM

William James and Focus

I've long been a fan of William James, and once wrote briefly about the connection between James's pragmatism and my doctoral work on knowledge-based systems. I was delighted yesterday to run across this quote from James's The Principles of Psychology, courtesy of 43 Folders and Linda Stone:

[Attention] is the taking possession by the mind, in clear and vivid form, of one out of what seem several simultaneously possible objects or trains of thought. ... It implies withdrawal from some things in order to deal effectively with others....

Prone as I am to agile moments, this message from James struck me in an interesting way. First of all, I occasionally battle the issue that Stone writes about, the to-do list that grows no matter productive I seem to be on a given day. (And on lazy summer June days, well, all bets are off.) James tells me that part of my problem isn't a shortage of time, but a lack of will to focus. I need to make better, more conscious choices about what tasks to add to the list. Kent Beck is fond of saying something to the effect that you may have too many things to do and too little time, but you ultimately have control over only one side of the equation. James would tell us the same thing.

My mind also made a connection from this quote to the agile software and test-driven development practice of working on small stories, on taking small steps. If I pick up a card with a single, atomic, well-defined feature to be added to my program, I am able to focus. What is the shortest step I can take and make this feature part of my code? No distractions, no Zerstreutheit. Though I have an idea in mind toward where my program is evolving, for this moment I attend to one small feature and make it work. Focus. James would be proud.

I think it's ironic in a way that one of the more effective ways to reach the state of flow is to decompose a task into the smallest of tasks and focus on them one at a time. The mind gets into a rhythm of red bar-green bar: select task, write code, refactor, and soon it is deep in its own world. I would like to be more effective at doing this in my non-programming duties. Perhaps if I keep James and his quote in mind, I can be.

This idea applies for me in other areas, in particular in running and training for particular events. Focusing each day on a particular goal -- intervals, Long Slow Distance, hill strength, and so on -- helps the mind to push aside its concerns with other parts of the game and attend to a particular kind of improvement. There is a great sense of relaxation in running super-hard repeats when the problem I've been having is, say, picking up pace late in a run. (I'd love to run super-hard repeats again some day soon, but I'm not there yet.)


Posted by Eugene Wallingford | Permalink | Categories: General, Running, Software Development

June 13, 2008 3:55 PM

Two Patterns Dealing with Side Effects

I ran across a pattern today that reminded of another I encountered while at ChiliPLoP. Both help developers deal with side effects, changes to a program's state. Let me share these patterns with you all, with a common explanation of their value.

Most programs written these days are in a style where setting and changing the values of one or more variables, via a sequence of imperative statements. Side effects are a common source of programmers' misunderstanding when reading code. A program can change a variable's state almost anywhere, and that makes reading any bit of code uneasy: "Do I really know what this variable means right now?" Using only local variables only in the context of a small procedure is one way to localize effects. Even still, problems can arise.

I won't try write full patterns for these. I'll write short patlets and give you links to the articles I read, which do a good job talking about the ideas.

Mutual Recursion with Side Effects

In Solving Every Sudoku Puzzle, Peter Norvig builds a Python program for the title task. About 40% of the way in, he says:

If you have two mutually-recursive functions that both alter the state of an object, try to move almost all the functionality into just one of the functions. Otherwise you will probably end up duplicating code.

Duplicate code is usually a bad thing, because it creates a problem for programmers keeping the copies in sync. Duplicate code that modifies state is especially bad, because it brings in the extra complication of making another procedure harder to understand.

Side Effects and Python's Default Parameters

Coincidentally, the second pattern involves Python, too. This time the pattern is Python-specific, addressing an issue with a language feature.

Context: You are writing a procedure with a default parameter.

Problem: The procedure needs to modify the default parameter. Python evaluates a default parameter's initial value only on the first call to the procedure.

Solution: Whenever the parameter is missing, initialize it within the method.

Tim Ottinger gives his implementation technique in Python's Mutable Default Problem:

def function( item, stuff=None ):
   stuff = stuff or []
   # ... modify stuff, etc.

This pattern allows the user to take advantage of the default parameter when he has no collection to send. It does so by following a principle laid out in the article Ottinger references: In Python, "don't use mutable objects as function defaults."

This pattern may not be Python-specific, because there may be other languages with this initialize-once behavior. It seems like a bug to me, not a feature, but I'm not a Python programmer and so can't speak authoritatively. But I am glad that Ruby doesn't do this.

~~~~~

Postscript: While preparing this article, I learned something new about Ruby, unrelated to this issue. It is possible to extract from a class a new class that has a subset of the original class's protocol. Very nice indeed!)


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

May 09, 2008 8:03 AM

Verdict Is In On One OOPSLA Submission

The verdict is in on the paper we wrote at ChiliPLoP and submitted to Onward!: rejected. (We are still waiting to hear back on our Educators' Symposium submission.) The reviews of our Onward! paper were mostly on mark, both on surface features (e.g., our list of references was weak) and on the deeper ideas we offer (e.g., questions about the history of studio approaches, and questions about how the costs will scale). We knew that this submission was risky; our time was simply too short to afford enough iterations and legwork to produce a good enough paper for Onward!.

I found it interesting that the most negative reviewer recommended the paper for acceptance. This reviewer was clearly engaged by the idea of our paper and ended up writing the most thorough, thoughtful review, challenging many of our assumptions along the way. I'd love to have the chance to engage this person in conversation at the conference. For now, I'll have to settle for pointing out some of the more colorful and interesting bits of the review.

In at least one regard, this reviewer holds the traditional view about university education. When it comes to the "significant body of knowledge that is more or less standard and that everyone in the field should acquire at some point in time", "the current lecture plus problem sets approach is a substantially more efficient and thorough way to do this."

Agreed. But isn't it more efficient to give the students a book to read? A full prof or even a TA standing in a big room is an expensive way to demonstrate standard bodies of knowledge. Lecture made more sense when books and other written material were scarce and expensive. Most evidence on learning is that lecture is actually much less effective than we professors (and the students who do well in lecture courses) tend to think.

The reviewer does offer one alternative to lecture: "setting up a competition based on mastery of these skills". Actually, this approach is consistent with the spirit of our paper's studio-based, apprenticeship-based, and project-based. Small teams working to improve their skills in order to win a competition could well inhabit the studio. Our paper tended to overemphasize the softer collaboration of an idyllic large-scale team.

This comment fascinated me:

Another issue is that this approach, in comparison with standard approaches, emphasizes work over thinking. In comparison with doing, for example, graph theory or computational complexity proofs, software development has a much lower ratio of thought to work. An undergraduate education should maximize this ratio.

Because I write a blog called Knowing and Doing, you might imagine that I think highly of the interplay between working and thinking. The reviewer has a point: an education centered on projects in a studio must be certain to engage students with the deep theoretical material of the discipline, because it is that material which provides the foundation for everything we do and which enables us to do and create new things. I am skeptical of the notion that an undergrad education should maximize the ratio of thinking to doing, because thinking unfettered by doing tends to drift off into an ether of unreality. However, I do agree that we must try to achieve an appropriate balance between thinking and doing, and that a project-based approach will tend to list toward doing.

One comment by the reviewer reveals that he or she is a researcher, not a practitioner:

In my undergraduate education I tried to avoid any course that involved significant software development (once I had obtained a basic mastery of programming). I believe this is generally appropriate for undergraduates.

Imagine the product of an English department saying, "In my undergraduate education I tried to avoid any course that involved significant composition (once I had obtained a basic mastery of grammar and syntax). I believe this is generally appropriate for undergraduates." I doubt this person would make much of a writer. He or she might be well prepared, though, to teach lit-crit theory at a university.

Most of my students go into industry, and I encourage them to take as many courses as they can in which they will build serious pieces of software with intellectual content. The mixture of thinking and doing stretches them and keeps them honest.

An education system that produces both practitioners and theoreticians must walk a strange line. One of the goals of our paper was to argue that a studio approach could do a better job of producing both researchers and practitioners than our current system, which often seems to do only a middling job by trying to cater to both audiences.

I agree wholeheartedly, though, with this observation:

A great strength of the American system is that it keeps people's options open until very late, maximizing the ability of society to recognize and obtain the benefits of placing able people in positions where they can be maximally productive. In my view this is worth the lack of focus.

My colleagues and I need to sharpen our focus so that we can communicate more effectively the notion that a system based on apprenticeship and projects in a studio can, in fact, help learners develop as researchers and as practitioners better than a traditional classroom approach.

The reviewer's closing comment expresses rather starkly the challenge we face in advocating a new approach to undergraduate education:

In summary, the paper advocates a return to an archaic system that was abandoned in the sciences for good reason, namely the inefficiency and ineffectiveness of the advocated system in transmitting the required basic foundational information to people entering the field. The write-up itself reflects naive assumptions about the group and individual dynamics that are required to make the approach succeed. I would support some of the proposed activities as part of an undergraduate education, but not as the primary approach.

The fact that so many university educators and graduates believe our current system exists in its current form because it is more efficient and effective than the alternatives -- and that it was designed intentionally for these reasons -- is a substantial cultural obstacle to any reform. Such is the challenge. We owe this reviewer our gratitude for laying out the issues so well.

In closing, I can't resist quoting one last passage from this review, for my friends in the other sciences:

The problem with putting students with no mastery of the basics into an apprenticeship position is that, at least in computer science, they are largely useless. (This is less true in sciences such as biology and chemistry, which involve shallower ideas and more menial activities. But even in these sciences, it is more efficient to teach students the basics outside of an apprenticeship situation.)

The serious truth behind this comment is the one that explains why building an effective computer science research program around undergraduates can be so difficult. The jocular truth behind it is that, well, CS is just plain deeper and harder! (I'll duck now.)


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

May 07, 2008 3:20 PM

Patterns as Descriptive Grammar

I've tried to explain the idea of software patterns in a lot of different ways, to a lot of different kinds of people. Reading James Tauber's Grammar Rules reminds me of one of my favorites: a pattern language is a descriptive grammar. Patterns describe how (good) programmers "really speak" when they are working in the trenches.

Talking about patterns as grammar creates the potential for the sort of misunderstanding that Tauber discusses in his entry. Many people, including many linguists, think of grammar rules as, well, rules. I was taught to "follow the rules" in school and came to think of the rules as beyond human control. Linguists know that the rules of grammar are man-made, yet some still seem to view them as prescriptive:

It is as if these people are viewing rules of grammar like they would road rules--human inventions that one may disagree with, but which are still, in some sense, what is "correct"...

Software patterns are rarely prescriptive in this sense. They describe a construct that programmers use in a particular context to balance the forces at play in the problem. Over time, they have been found useful and so recur in similar contexts. But if a programmer decides not to use a pattern in a situation where it seems to apply, the programmer isn't "wrong" in any absolute sense. But he'll have to resolve the competing forces in some other way.

While the programmer isn't wrong, other programmers might look at him (or, more accurately, his program) funny. They will probably ask "why did you do it that way?", hoping to learn something knew, or at least confirm that the programmer has done something oddly.

This is similar to how human grammar works. If I say, "Me wrote this blog", you would be justified in looking at me funny. You'd probably think that what I speaking incorrectly.

Tauber points out that, while I might be violating the accepted rules of grammar, I'm not wrong in any absolute sense:

... most linguists focus on modeling the tacit intuitions native speakers have about their language, which are very often at odds with the "rules of grammar" learnt at school.

He gives a couple of examples of rules that we hear broken all of the time. For example, native speakers of English almost always say "It's me", not "It's I", though that violates the rules of nominative and accusative case. Are we all wrong? In Sr. Jeanne's 7th-grade English class, perhaps. But English grammar didn't fall from the heavens as incontrovertible rules; it was created by humans as a description of accepted forms of speech.

When a programmer chooses not to use a pattern, other programmers are justified in taking a second look at the program and asking "why?", but they can't really say he's guilty of anything more than doing things differently.

Like grammar rules, some patterns are more "right" than others, in the sense that it's less acceptable to break some than others. I can get away with "It's me", even in more formal settings, but I cannot get away with "Me wrote this blog", even in the most informal settings. An OO programmer might be able get away with not using the Chain of Responsibility pattern in a context where it applies, but not using Strategy or Composite in appropriate contexts just makes him look uninformed, or uneducated.

A few more thoughts:

So, patterns are not like a grammar for programming language, which is prescriptive. To speak Java at all, you have to follow the rules. They are like the grammar of a human language, which model observations about how people speak in the wild.

As a tool for teaching and learning, patterns are so useful precisely because they give us a way to learn accepted usages that go beyond the surface syntactic rules of a language. Even better, the pattern form emphasizes documenting when a construct works and why. Patterns are better than English grammar in this regard, at least better than the way English grammar is typically taught to us as schoolchildren.

There are certainly programmers, software engineers, and programming language theorists who want to tell us how to program, to define prescriptive rules. There can be value in this approach. We can often learn something from a model that has been designed based on theory and experience. But to me prescriptive models for programming are most useful when we don't feel like we have to follow them to the letter! I want to be able to learn something new and then figure out how I can use it to become a better programmer, not a programmer of the model's kind.

But there is also a huge, untapped resource in writing the descriptive grammar of how software is built in practice. It is awfully useful to know what real people do -- smart, creative people; programmers solving real problems under real constraints. We don't understand programming or software development well enough yet not to seek out the lessons learned by folks working in the trenches.

This brings to mind a colorful image, of software linguists venturing into the thick rain forest of a programming ecosystem, uncovering heretofore unexplored grammars and cultures. This may not seem as exotic as studying the Pirahã, but we never know when some remote programming tribe might upend our understanding of programming...


Posted by Eugene Wallingford | Permalink | Categories: Computing, Patterns, Software Development

April 23, 2008 6:16 PM

The Small Doses Pattern

Update: Added a known use contributed by Joe Bergin. -- 05/19/08.

Also Known As    Frequent Releases

From Pattern Language    Graduate Student

You are writing a large document that one or more other people must read and provide feedback on before it is distributed externally.

The archetype is a master's thesis or doctoral dissertation, which must be approved by a faculty committee.

You want to give your reviewers the best document possible. You want them to give you feedback and feel good about approving the document for external distribution.

You want to publish high-quality work. You would also like to have your reviewers see only your best work, for a variety of reasons. First, you respect them and are thankful for their willingness to help you. Second, they often have the ability to help you further in the future, in the form of jobs or recommendations. Good work will impress your reviewers more than weaker work. A more complete and mature document is more likely to resemble the final result than a rougher, earlier version.

In order to produce a document of the highest quality, you need time -- time to research, write, and revise. This delays your opportunity to distribute it to your reviewers. It also delays their opportunity to give you feedback.

Your reviewers are busy. They have their own work to do and are often volunteering their time to serve you.

Big tasks require a lot of time. If a task takes a lot of time to do, some people face a psychological barrier to starting the task.

A big task decomposed into several smaller tasks may take as much time as the big task, or more, but each task takes a smaller time. It is often easier to find time in small chunks, which makes it easier to start on the task in the first place.

The sooner your reviewers are able to read parts of the document, the sooner they will be able to give you feedback. This feedback helps you to improve the document, both in the large (topic, organization) and the small (examples, voice, illustrations, and so on).

Therefore:

Distribute your document to reviewers periodically over a relatively drawn out period. Early versions can be complete parts of the document, or rough versions of the entire document.

In the archetypal thesis, you might give the reviewers one chapter per week, or you might give a whole thesis in which each part is in various stages of completeness.

There is certainly a trade-off between the quality of a document and the timeliness of delivery. Don't worry; this is just a draft. You are always free to improve and extend your work. Keep in mind that there is also a trade-off between the quality of a document and the amount of useful feedback you are able to incorporate.

There is value in distributing even a very rough or incomplete document at regular intervals. If reviewers read the relatively weak version and make suggestions, they will feel valuable. If they don't read it, they won't know or mind that you have made changes in later versions. Furthermore, they may feel wise for not having wasted their time on the earlier draft!

With the widespread availability of networks, we can give our reviewers real-time access to an evolving document in the form of an-line repository. In such a case, Small Doses may take the form of comments recorded as each change is committed to the repository. It is often better for your reviewers if you give them periodic descriptions of changes made to the document, so that they don't have to wade through minutiae and can focus on discrete meaningful jumps in the document.

I have seen Small Doses work effectively in a variety of academic contexts, from graduate students writing theses to instructors writing lecture notes and textbooks for students. I've seen it work for master's students and doctoral students, for text and code and web sites. Joe Bergin says that this pattern is an essential feature of the Doctor of Professional Studies program at Pace University. Joe has documented patterns for succeeding in the DPS program. (If you know of particularly salient examples of Small Doses, I'd love to hear them.)

Often times, the value of Small Doses is demonstrated best in the results of its applying its antipattern, Avalanche. Suppose you are nearing a landmark date, say, the deadline for graduation or the end of spring semester, when faculty will scatter for the summer. You dump a 50-, 70-, or 100+-page document on your thesis committee. In the busy time before the magic date, committee members have a difficulty finding time to read the whole document. Naturally, they put off reading it. Soon they fall way behind and have a hard time meeting the deadline -- and they blame you for the predicament, for unrealistic expectations. Of course, had you given the committee a chapter at a time for 5 or 6 weeks leading up to the magic date, some committee members would still have fallen behind reading it, because they are distracted with their own work. But then you could blame the them for not getting done!

Related Patterns    Extreme Programming and other agile software methodologies encourage Short Iterations and Frequent Releases. Such frequent releases are the Small Doses of the software development world. They enable more continuous feedback and allow the programmers to improve the quality of the code based on what they learn. The Avalanche antipattern is the source of many woes in the world of software, in large part due to the lack of feedback they afford from users and clients.

I learned the Small Doses pattern from Carl Page, my Artificial Intelligence II professor at Michigan State University in 1987. Professor Page was a bright guy and very good computer scientist, with an often dark sense of humor. He mentored his students and advisees with sardonic stories like Small Doses. He was also father to another famous Page, Larry.


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

April 08, 2008 9:11 PM

The Worst Kind of Job

Comedian Rodney Laney

Yesterday I was listening to comedian Rodney Laney do a bit called "Old Jobs". He explained that the best kind of job to have is a one-word job that everyone understands. Manager, accountant, lawyer -- that's good. But if you have to explain what you do, then you don't have a good job. "You know the inside of the pin has these springs? I put the springs on the inside of the pins." And then you have to explain why you matter... "Without me, the pins wouldn't go click." Bad job.

Okay, computer scientists and software developers, raise your hands if you've had to explain what you do to a new acquaintance at a party. To a curious relative? I should say "tried to explain", because my own attempts come up short far too often.

I think good Rodney has nailed a major flaw in being a computer scientist.

Sadly, going with the one-word job title of "programmer" doesn't help, and the people who think know what a programmer is often don't really know.

Even still, I like what I do and know why it's a great job.

(Thanks to the wonders of the web, you can watch another version of Laney's routine, Good Jobs, on-line at Comedy Central. I offer no assurance that you'll like it, but I did.)


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

April 03, 2008 4:39 PM

Astrachan's Law for a New Generation?

Owen is reputed to have said something like "Don't give as a programming assignment something the student could just as easily do by hand." (I am still doing penance, even though Lent ended two weeks ago.) This has been dubbed Astrachan's Law, perhaps by Nick Parlante. In the linked paper, Parlante says that showmanship is the key to the Law, that

A trivial bit of code is fine for the introductory in-lecture example, but such simplicity can take the fun out of an assignment. As jaded old programmers, it's too easy to forget the magical quality that software can have, especially when it's churning out an unimaginable result. Astrachan's Law reminds us to do a little showing off with our computation. A program with impressive output is more fun to work on.

I think of this Astrachan's Law in a particular way. First, I think that it reaches beyond showmanship: Not only do students have less fun working on trivial programs, they don't think that trivial programs are worth doing at all -- which means they may not practice enough or at all. Second, I most often think of Astrachan's Law as talking about data. When we ask students to convert Fahrenheit to Celsius, or to sum ten numbers entered at the keyboard, we waste the value of a program on something that can be done faster with a calculator or -- gasp! -- a pencil and paper. Even if students want to know the answer to our trivial assignment, they won't see a need to master Java syntax to find it. You don't have to go all the way to data-intensive computing, but we really should use data sets that matter.

Yesterday, I encountered what might be a variant or extension of Astrachan's Law.

John Zelle of Wartburg College gave a seminar for our department on how to do virtual reality "on a shoestring" -- for $2000 or less. He demonstrated some of his equipment, some of the software he and his students have written, and some of the programs written by students in his classes. His presentation impressed me immensely. The quality of the experience produced by a couple of standard projects, a couple of polarizing filters, and a dollar pair of paper 3D glasses was remarkable. On top of that, John and his students wrote much of the code driving the VR, including the VR-savvy presentation software.

Toward the end of his talk, John was saying something about the quality of the VR and student motivation. He commented that it was hard to motivate many students when it came to 3D animation and filmmaking these days because (I paraphrase) "they grow up accustomed to Pixar, and nothing we do can approach that quality". In response to another question, he said that a particular something they had done in class had been quite successful, at least in part because it was something students could not have done with off-the-shelf software.

These comments made me think about how, in the typical media computation programming course, students spend a lot of time writing code to imitate what programs such as Photoshop and Audacity do. To me, this seems empowering: the idea that a freshman can write code for a common Photoshop filter in a few lines of Java or Python, at passable quality, tells me how powerful being able to write programs makes us.

But maybe to my students, Photoshop filters have been done, so that problem is solved and not worthy of being done again. Like so much of computing, such programs are so much a part of the background noise of their lives that learning how to make them work is as appealing to them as making a ball-point pen is to people of my age. I'd hope that some CS-leaning students do want to learn such trivialities, on the way to learning more and pushing the boundaries, but there may not be enough folks of that bent any more.

On only one day's thought, this is merely a conjecture in search of supporting evidence. I'd love to here what you think, whether pro, con, or other.

I do have some anecdotal experience that is consistent in part with my conjecture, in the world of 2D graphics. When we first started teaching Java in a third-semester object-oriented programming course, some of the faculty were excited by what we could do graphically in that course. It was so much more interesting than some of our other courses! But many students yawned. Even back in 1997 or 1998, college students came to us having experienced graphics much cooler than what they could do in a first Java course. Over time, fewer and fewer students found the examples knock-out compelling; the graphics became just another example.

If this holds, I suppose that we might view it as a new law, but it seems to me a natural extension of Astrachan's Law, a corollary, if you will, that applies the basic idea into the realm of application, rather than data.

My working title for this conjecture is the Pixar Effect, from the Zelle comment that crystallized it in my mind. However, I am open to someone else dubbing it the Wallingford Conjecture or the Wallingford Corollary. My humility is at battle with my ego.


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

April 01, 2008 5:45 PM

Ruby Tuesday

Is anybody home? After a flurry of writing from SIGCSE, I returned home to family time and plenty of work at the office. The result has been one entry in ten days. I look forward to finishing up my SIGCSE reports, but they appear to lie forward a bit, as the next week or so are busy. I have a few new topics in the hopper waiting for a few minutes to write as well.

One bit of good news is that part of my busy-ness this week and next is launching the third iteration of my language topics course. We've done bash and PHP and are now moving on to Ruby, one of my favorite languages. Shell scripting is great, but its tools are too limited to make writing bigger programs fun. PHP was better than I expected, but in the end it is really about building web sites, not writing more general programs. (And after a few weeks of using the language, PHP's warts started to grate on me.)

Ruby is... sublime. It isn't perfect, of course, but even its idiosyncrasies seem to get out of my way when I am deep in code. I looked up the definition of 'sublime', as I sometimes do when I use a word which is outside my daily working vocabulary or is misused enough in conversation that I worry about misusing it myself. The first set of definitions have a subtlety reminiscent of Ruby. To "vaporize and then condense right back again" sounds just like Ruby getting out of my way, only for me to find that I've just written a substantial program in a few lines. (My favorite, though, is "well-meaning ineptitude that rises to empyreal absurdity"!)

This is my first time to teach Ruby formally in a course. I hope to use this new course beginning as a prompt to write a few entries on Ruby and what teaching it is like.

There are many wonderful resources for learning about and programming in Ruby. I've suggested that my students use the pickaxe book as a primary reference, even if they use the first edition, a complete version of which is available on-line. In today's class, though, I used a simple evolutionary example from Brian Marick's book Everyday Scripting with Ruby. I hesitated to use this book as the student's primary source because it was originally written for tester's without any programming background, and my course is for upper-division CS majors with several languages under their belts. But Brian works through several examples in a way that I find compelling, and I think I can base a few solid sessions on one or two of them.

This book makes me wonder how easy it would be to re-target a book from an audience like non-programming testers to an audience of scripting-savvy programmers who want to learn Ruby's particular yumminess. I know that in the course of writing the book Brian generalized his target audience from testers to the union of three different audiences (testers, business analysts, and programmers). Maybe after I've lived with the book and an audience of student programmers I'll have a better sense of how well the re-targeting worked. If it works for my class, then I'll be inclined to adopt it for the next offering of this course.

Anyway, today we evolved a script for diffing to directories of files for a tester. I liked the flow of development and the simple script that resulted. Now we will move on to explore language features and their use in greater depth. One example I hope to work through soon, perhaps in conjunction with Ruby's regular expressions, is "Finding Things", Tim Bray's chapter in Beautiful Code.

Oh, and I must say that this is the first time that one of my courses has a theme song -- and a fine theme song, indeed. Now, if only someone would create a new programming language called "Angie", I would be in heaven.


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

March 20, 2008 4:21 PM

SIGCSE Day 2 -- Plenary Address by Marissa Mayer

[A transcript of the SIGCSE 2008 conference: Table of Contents]

Marissa Mayer

The second day of the conference opened with the keynote address by Google's VP of Search Products and User Experience, Marissa Mayer. She was one of the early hires as the company expanded beyond the founders, and from her talk it's clear that she has been involved with a lot of different products in her time there. She is also something the discipline of computer science could use more of, a young woman in a highly-visible technical and leadership and roles. Mayer is a great ambassador for CS as it seeks to expand the number of female high-school and college students.

This talk was called Innovation, Design, and Simplicity at Google and illustrated some of the ways that Google encourages creativity in its employees and gets leverage from their ideas and energy. I'll drop some of her themes into this report, though I imagine that the stories I relate in between may not always sync up. Such is the price of a fast-moving talk and five days of receding memory.

Creativity loves constraint.

I have written on this topic a few times, notably in the context of patterns, and it is a mantra for Google, whose home page remains among the least adorned on the web. Mayer said that she likes to protect its minimalist feel even when others would like to jazz it up. The constraints of a simple page force the company to be more creative in how it presents results. I suspect it also played a role in Google developing its cute practice of customizing the company logo in honor of holidays and other special events. Mayer said that minimalism may be a guide now, but it was not necessarily a reason for simplicity in the beginning. Co-founder Sergey Brin created the first Google home page, and he famously said, "I don't do HTML."

Mayer has a strong background both in CS and in CS education, having worked with the undergrad education folks at Stanford as a TA while an undergrad. (She said that it was Eric Roberts who first recommended Google to her, though at the time he could not remember the company's name!) One of her first acts as an employee was to run a user study on doing search from the Google homepage. She said that when users first sat down and brought up the page, they just sat there. And sat there. They were "waiting for the rest of it"! Already, users of the web were already accustomed to fancy pages and lots of graphics and text. She said Google added its copyright tag line at the bottom of the page to serve as punctutation, to tell the user that that's all there was.

Search is a fixed focus at Google, not a fancy user interface. Having a simple UI helps to harness the company's creativity.

Work on big problems, things users do every day.

Work on things that are easy to explain and understand.

Mayer described in some detail the path that a user's query follows from her browser to Google and back again with search results. Much of that story was as expected, though I was surprised by the fact that there are load balancers to balance the load on the load balancers that hand off queries to processors! Though I might have thought that another level of indirection would slow the process it down, indeed it is necessary in order to ensure that the system doesn't slow down. Even with the web server and the ad server and the mixers, users generally see their results in about 0.2 seconds. How is that for a real-time constraint to encourage technical creativity?

Search is the #2 task performed on the web. E-mail is (still) #1. Though some talking heads have begun to say that search is a mature business in need of consolidation, Google believes that search is just getting started. We know so little about how to do it well, how to meet the user's needs, and how to uncover untapped needs. Mayer mentioned a problem familiar to this old AI guy: determining the meaning of the words used in a query so that they can serve pages that match the user's conceptual intent. She used a nice example that I'll probably borrow the next time I teach AI. When a user asks for an "overhead view", he almost always wants to see a picture!

This points in the direction of another open research area, universal search. The age in which users want to search for text pages, images, videos, etc., as separate entities has likely passed. That partitioning is a technical issue, not a user's issue. The search companies will have to find a way to mix in links to all kinds of media when they serve results. For Google, this also means figuring out how to maintain or boost ad revenue when doing so.

Ideas come from everywhere.

Mayer gave a few examples. One possible source is office hours, which are usually thought of as an academic concept but which she has found useful in the corporate world. She said that the idea for Froogle walked through her office door one day with the scientist who had it.

Another source is experiments. Mayer told a longer story about Gmail. The company was testing it in-house and began to discuss how they could make many from it. She suggested the industry-standard model of giving a small amount of storage for free and then charging for more. This might well have worked, because Google's cost structure would allow it to offer much larger amounts at both pricing levels. But a guy named Paul -- he may be famous, but I don't know his last name -- suggested advertising. Mayer pulled back much as she expected users to do; do people really want Google to read their e-mail and serve ads? Won't that creep them out?

She left the office late that night believing that the discussion was on hold. She came back to work the next morning to find that Paul had implemented an experimental version in a few hours. She was skeptical, but the idea won her over when the system began to serve ads that were perfectly on-spot. Some folks still prefer to read e-mail without ads, but the history of Gmail has shown just how successful the ad model can be.

The insight here goes beyond e-mail. The search ad data base can be used on any paged on the web. This is huge... Search pages account for about 5% of the pages served on the web. Now Google knew that they could reach the other 95%. How's that for a business model?

To me, the intellectual lesson is this:

If you have an idea, try it out.

This is a power that computer programmers have. It is one of the reasons that I want everyone to be able to program, if only a little bit. If you have an idea, you ought to be able to try it out.

Not every idea will lead to a Google, but you never know which ones will.

Google Books started as a simple idea, too. A person, a scanner, and a book. Oh, and a metronome -- Mayer said that when she was scanning pages she would get out of rhythm with the scanner and end up photocopying her thumbs. Adding a metronome to the system smoothed the process out.

... "You're smart. We're hiring." worked remarkably well attracting job candidates. We programmers have big egos! Google is one of the companies that has made it okay again to talk about hiring smart people, not just an army of competent folks armed with a software development process, and giving them the resources they need to do big things.

Innovation, not instant perfection.

Google is also famous for not buying into the hype of agile software development. But that doesn't mean that Google doesn't encourage a lot of agile practices. For example, at the product level, it has long practiced a "start simple, then grow" philosophy.

Mayer contrasted two kinds of programmers, castle builders and nightly builders. Companies are like that, too. Apple -- at least to outside appearances -- is a castle-building company. Every once in a while, Steve Jobs et al. go off for a few years, and then come back with an iPod or an iPhone. This is great if you can do it, but only a few companies can make it work. Google is more of a nightly builder. Mayer offered Google News as a prime example -- it went through 64 iterations before it reached its current state. Building nightly and learning from each iteration is often a safer approach, and even companies that are "only good" can make it work. Sometimes, great companies are the result.

Data is a-political.

Mayer didn't mean Republican versus Democrat here, rather that well-collected data provide a more objective basis for making decisions than the preferences of a manager or the guesses of a designer or programmer. Designing an experiment that will distinguish the characteristics you are in interested, running it, and analyzing the data dispassionately are a reliable way to make good decisions. Especially when a leader's intuition is wrong, such as Mayer's was on Gmail advertising.

She gave a small plug for using Google Trends as a way to observe patterns in search behavior when they might give an idea about a question of interest. Query volume may not not change much, but the content of the queries does.

Users, users, users.

What if some users want more than the minimalist white front page offered by Google? In response to requests from a relatively small minority of users -- and the insistent voices of a few Google designers -- iGoogle is an experiment in offering a more feature-filled portal experience. How well will it play? As is often the case, the data will tell the story.

Give license to dream.

Mayer spent some time talking about the fruits of Google's well-known policy of 20% Time, whereby every employee is expected to spend 1/5 of his or her time working on projects of personal interest. While Google is most famous for this policy these days, like most other ideas it isn't new. At ChiliPLoP this week, Richard Gabriel reported that Eric Schmidt took this idea to Google with him when he left Sun, and Pam Rostal reported that 3M had a similar policy many years ago.

But Google has rightly earned its reputation for the fruits of 20% Time. Google News. Google Scholar. Google Alerts. Orkut. Froogle Wireless. Much of Google Labs. Mayer said that 50% of Google's new products come from these projects, which sounds like a big gain in productivity, not the loss of productivity that skeptics expect.

I have to think that the success Google has had with this policy is tied pretty strongly with the quality of its employees, though. This is not meant to diss the rest of us regular guys, but you have to have good ideas and the talent to carry them out in order for this to work well. That said, these projects all resulted from the passions of individual developers, and we all have passions. We just need the confidence to believe in our passions, and a willingness to do the work necessary to implement them.

Most of the rest of Mayer's talk was a litany of these projects, which one wag in the audience called a long ad for the goodness of Google. I wasn't so cynical, but I did eventually tire of the list. One fact that stuck with me was the description of just how physical the bits of Google Earth are. She described how each image of the Earth's surface needs to be photographed at three or four different elevations, which requires three or four planes passing over every region. Then there are the cars driving around taking surface-level shots, and cameras mounted to take fixed-location shots. A lot of physical equipment is at work -- and a lot of money.

Share the data.

This was the last thematic slogan Mayer showed, though based on the rest of the talk I might rephrase it as the less pithy "Share everything you can, especially the data." Much of Google's success seems based in a pervasive corporate culture of sharing. This extends beyond data to ideas. It also extends beyond Google campus walls to include users.

The data-sharing talk led Mayer to an Easter Egg she could leave us. If you check Google's Language Tools page, you will see Bork, Bork, Bork, a language spoken (only?) by the Swedish chef on the Muppets. Nonetheless, the Bork, Bork, Bork page gets a million hits a year (or was it a day?). Google programmers aren't the only ones having fun, I guess.

Mayer closed with suggestions for computer science educators. How might we prepare students better to work in the current world of computing? Most of her recommendations are things we have heard before: build and use applications, work on large projects and in teams, work with legacy code, understand and test at a large scale, and finally pay more attention to reliability and robustness. Two of her suggestions, though, are ones we don't hear as often and link back to key points in her talk: work with and understand messy data, and understand how to use statistics to analyze the data you collect.

After the talk, folks in the audience asked a few questions. One asked how Google conducts user studies. Mayer described how they can analyze data of live users by modding the key in user cookies to select 1/10 or 1/1000 of the user population, give those users a different experience, and then look at characteristics such as click rate and time spent on page by these users compared to the control group.

The best question was in fact a suggestion for Google. Throughout her talk, Mayer referred repeatedly to "Google engineers", the folks who come up with neat ideas, implement them in code, test them, and then play a big role in selling them to the public. The questioner pointed out that most of those "engineers" are graduates of computer science programs, including herself, Sergey Brin, and Larry Page. He then offered that Google could do a lot to improve the public perception of our discipline if it referred to its employees as computer scientists.

I think this suggestion caught Mayer a little off-guard, which surprised me. But I hope that she and the rest of Google's leadership will take it to heart. In a time when it is true both that we need more computer science students and that public perception of CS as a discipline is down, we should be trumpeting the very cool stuff that computer scientists are doing at places like Google.

All in all, I enjoyed Mayer's talk quite a bit. We should try to create a similarly creativity-friendly environment for our students and ourselves. (And maybe work at a place like Google every so often!)


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

March 19, 2008 12:40 AM

A Change in Direction at ChiliPLoP

As I mentioned in my last SIGCSE entry, I have moved from carefree Portland to Carefree, Arizona, for ChiliPLoP 2008. The elementary patterns group spent yesterday, its first, working on the idea of integrating large datasets into the CS curriculum. After a few years of working on specific examples, both stand-alone and running, we started this year thinking about how CS students can work on real problems from many different domains. In the sciences, that often means larger data sets, but more important it means authentic data sets, and data sets that inspire students to go deeper. On the pedagogical side of the ledger, much of the challenge lies in finding and configuring data sets so that they can used reliably and without unnecessary overhead placed on the adopting instructor.

This morning, we volunteered to listen to a presentation by the other hot topic group on its work from yesterday: a "green field" thought experiment designing an undergrad CS program outside of any constraints from the existing university structure. This group consists of Dave West and Pam Rostal, who presented an earlier version of this work at the OOPSLA 2005 Educators' Symposium, and Richard Gabriel, who brings to the discussion not only an academic background in CS and a career in computer science research and industry but also an MFA in poetry. Perhaps the key motivation for their hot topic is that most CS grads go on to be professional software developers or CS researchers, and that our current way of educating them doesn't do an ideal job of preparing grads for either career path.

Their proposal is much bigger than I can report here. They started by describing a three-dimensional characterization of different kinds of CS professionals, including provocative and non-traditional labels as "creative builder", "imaginative researcher", and "ordinologist". The core of the proposal is the sort of competency-based curriculum that West and Rostal talked about at OOPSLA, but I might also describe it as studio-based, apprenticeship-based, and project-based. One of their more novel ideas is that students would learn everything they need for a liberal arts, undergraduate computer science education through their software projects -- including history, English, writing, math, and social science. For example, students might study the mathematics underlying a theorem prover while building a inference engine, study a period of history in order to build a zoomable timeline on the web for an instructional web site, or build a Second Life for a whole world in ancient Rome.

In the course of our discussion, the devil's advocates in the room raised several challenging issues, most of which the presenters had anticipated. For example, how do the instructors (or mentors, as they called them) balance the busy work involved in, say, the students implementing some Second Life chunk with the content the students need to learn? Or how does the instructional environment ensure that students learn the intellectual process of, say, history, and not just impose a computer scientist's worldview on history? Anticipating these concerns does not mean that they have answers, only that they know the issues exist and will have to be addressed at some point. But this isn't the time for self-censorship... When trying to create something unlike anything we see around us, the bigger challenge is trying to let the mind imagine the new thing without prior restraint from the imperfect implementations we already know.

We all thought that this thought experiment was worth carrying forward, which is where the change of direction comes in. While our group will continue to work on the dataset idea from yesterday, we decided in the short term to throw our energies into the wild idea for reinventing CS education. The result will be two proposals to OOPSLA 2008: one an activity at the Educators' Symposium, and the other an Onward! paper. This will be my first time as part of a proposal to the Onward! track, which is both a cool feeling and an intimidating prospect. We'll see what happens.


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

March 13, 2008 7:22 PM

Notes on SIGCSE 2008: Table of Contents

This set of entries records my experiences at SIGCSE 2008, in Portland, Oregon, March 12-16. I'll update it as I post new pieces about the conference. One of those entries will explain why my posts on SIGCSE may come more slowly than they might.

Primary entries:

Ancillary entries:


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

March 05, 2008 2:05 PM

And the Winner Is...

The Prometheus Awards are the Iowa tech industry equivalent of the Academy Awards. At last night's 2008 award ceremony, CS alumni from my school made a good showing.

T8Design won Software Company of the Year in the Small Company Division. Alumnus Wade Arnold is one of T8's co-founders, its former CTO, and its current CEO. Wade accepted the statuette and gave a fine acceptance speech. At least two other alumni were there in the T8 delegation, and it was good to be able to congratulate them all in person.

Alliance Technologies won the award for IT Service Provider of the Year. Alumnus and UNI CS advisory board member Mike Lang, CEO and President of Alliance, represented the company on the dais.

There were two other software connections to our program among the winners. Alumnus Tony Bibbs was part of the team that wrote one of the pieces of software nominated for Best Innovation in Government, which was won by ABC Virtual. And the most distant connection involved Express Auto, which won Top Growth Company of the Year in the Under $25M Division. One of the first programs that got Express Auto off the ground back in the mid-1990s was written by a UNI alumnus and CS advisory board member Fred Zelhart.

It was a good evening for UNI Computer Science alumni, and a good night for this CS prof. With the exception of Mike, who graduated the year before I came here, I had all of these entrepreneurs and developers as students in class, and now I work with Mike, Fred, and Wade on an ongoing basis. I feel a little paternal -- now fraternal -- pride!


Posted by Eugene Wallingford | Permalink | Categories: Software Development

March 02, 2008 2:03 PM

Them's Fighting Words

This provocative statement appears in the Roly Perera essay that I mentioned recently:

All I know is that if there is a place for post-modernist, lit-crit, social constructivist thinking in the modern world, it's nowhere near the field of computing.

Robert Biddle and James Noble may have a duel on their hands (PDF)! I think that we have the makings of an outstanding OOPSLA 2008 panel.

I'd certainly like to hear more from Perera if he has more ideas of this sort:

... emergent behaviours are in a sense dual to the requirements on a solution. Requirements are known and obligate the system in certain ways, whereas emergent behaviours ("emergents", one could call them) are those which are permitted by the system, but which were not known a priori.

This is an interesting analogy, one I'd like to think more about. For some reason, it reminds of Jon Postel's dictum about protocol design, "Be liberal in what you accept, and conservative in what you send" and Bertrand Meyer's ideas about design by contract.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

March 01, 2008 3:39 PM

Toward Less Formal Software

This week I ran across Jonathan Edwards's review of Gregor Kiczales's OOPSLA 2007 keynote address, "Context, Perspective and Programs" (which is available from the conference podcast page). Having recently commented on Peter Turchi's keynote, I figured this was a good time to go back and listen to all of Gregor's again. I first listened to part of it back when I posted it to the page, but I have to admit that I didn't understand it all that well then. So a second listen was warranted. This time I had access to his slides, which made a huge difference.

In his talk, Kiczales tries to bring together ideas from philosophy, language, and our collective experience writing software to tackle a problem that he has been working around his whole career: programs are abstractions, and any abstraction represents a particular point of view. Over time, the point of view changes, which means that the program is out of sync. Software folks have been thinking about ways to make programs capable of responding naturally as their contexts evolve. Biological systems have offered some inspiration in the last decade or so. Kiczales suggests that computer science's focus on formality gets in the way of us finding a good answer to our problem.

Some folks took this suggestion as meaning that we would surrender all formalism and take up models of social negotiation as our foundation. Roly Perera wrote a detailed and pointed review of this sort. While I think Perera does a nice job of placing Kiczales's issues in their philosophical context, I do not think Kiczales was saying that we should go from being formal to being informal. He was suggesting that we shouldn't have to go from being completely formal to being completely informal; there should be a middle ground.

Our way of thinking about formality is binary -- is that any surprise? -- but perhaps we can define a continuum between the two. If so, we could write our program at an equilibrium point for the particular context it is in and then, as the context shifts, allow the program to move along the continuum in response.

Now that I understand a little better what Kiczales is saying, his message resonates well with me. It sounds a lot like the way a pattern balances the forces that affect a system. As the forces change, a new structure may need to emerge to keep the code in balance. We programmers refactor our code in response to such changes. What would it be like for the system to recognize changes in context and evolve? That's how natural systems work.

As usual, Kiczales is thinking thoughts worth thinking.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Patterns, Software Development

February 24, 2008 12:48 PM

Getting Lost

While catching up on some work at the office yesterday -- a rare Saturday indeed -- I listened to Peter Turchi's OOPSLA 2007 keynote address, available from the conference podcast page. Turchi is a writer with whom conference chair Richard Gabriel studied while pursuing his MFA at Warren Wilson College. I would not put this talk in the same class as Robert Hass's OOPSLA 2005 keynote, but perhaps that has more to do with my listening to an audio recording of it and not being there in the moment. Still, I found it to be worth listening as Turchi encouraged us to "get lost" when we want to create. We usually think of getting lost as something that happens to us when we are trying to get somewhere else. That makes getting lost something we wish wouldn't happen at all. But when we get lost in a new land inside our minds, we discover something new that we could not have seen before, at least not in the same way.

As I listened, I heard three ideas that captured much of the essence of Turchi's keynote. First was that we should strive to avoid preconception. This can be tough to do, because ultimately it means that we must work without knowing what is good or bad! The notions of good and bad are themselves preconceptions. They are valuable to scientists and engineers as they polish up a solution, but they often are impediments to discovering or creating a solution in the first place.

Second was the warning that a failure to get lost is a failure of imagination. Often, when we work deeply in an area for a while, we sometimes feel as if we can't see anything new and creative because we know and understand the landscape so well. We have become "experts", which isn't always as dandy a status as it may seem. It limits what we see. In such times, we need to step off the easy path and exercise our imaginations in a new way. What must I do in order to see something new?

This leads to the third theme I pulled from Turchi's talk: getting lost takes work and preparation. When we get stuck, we have to work to imagine our way out of the rut. For the creative person, though, it's about more about getting out of a rut. The creative person needs to get lost in a new place all the time, in order to see something new. For many of us, getting lost may seem like as something that just happens, but the person who wants to be lost has to prepare to start.

Turchi mentioned Robert Louis Stevenson as someone with a particular appreciation for "the happy accident that planning can produce". But artists are not the only folks who benefit from these happy accidents or who should work to produce the conditions in which they can occur. Scientific research operates on a similar plane. I am reminded again of Robert Root-Bernstein's ideas for actively engaging the unexpected. Writers can't leave getting lost to chance, and neither can scientists.

Turchi comes from the world of writing, not the world of science. Do his ideas apply to the computer scientist's form of writing, programming? I think so. A couple of years ago, I described a structured form of getting lost called air-drop programming, which adventurous programmers use to learn a legacy code base. One can use the same idea to learn a new framework or API, or even to learn a new programming language. Cut all ties to the familiar, jump right in, and see what you learn!

What about teaching? Yes. A colleague stopped by my office late last week to describe a great day of class in which he had covered almost none of what he had planned. A student had asked a question whose answer led to another, and then another, and pretty soon the class was deep in a discussion that was as valuable, or more, than the planned activities. My colleague couldn't have planned this unexpectedly good discussion, but his and the class's work put them in a position where it could happen. Of course, unexpected exploration takes time... When will they cover all the material of the course? I suspect the students will be just fine as they make adjustments downstream this semester.

What about running? Well, of course. The topic of air-drop programming came up during a conversation about a general tourist pattern for learning a new town. Running in a new town is a great way to learn the lay of the land. Sometimes I have to work not to remember landmarks along the way, so that I can see new things on my way back to the hotel. As I wrote after a glorious morning run at ChiliPLoP three years ago, sometimes you run to get from Point A to Point B; sometimes, you should just run. That applies to your hometown, too. I once read about an elite women's runner who recommended being dropped off far from your usual running routes and working your way back home through unfamiliar streets and terrain. I've done something like this myself, though not often enough, and it is a great way to revitalize my running whenever the trails start look like the same old same old.

It seems that getting lost is a universal pattern, which made it a perfect topic for an OOPSLA keynote talk.


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

February 21, 2008 7:37 PM

Father, Forgive Me

... though I can't in good conscience say, "for I know not what I do."

1. Write a script named simple-interest.php that defines a function to compute the simple interest on an amount, given the amount, annual interest rate, and number of months. Your script should apply the function to its command-line arguments, which are those same values.

The rest of my PHP class's first homework is more reasonable, with a couple of problems repeated from the bash class's first assignment as a way for students to get a sense of trade-offs between shell programming and scripting in a more general-purpose language.

Still, I had to squeeze my eyes shut tight to hit the key that published this assignment. I keep telling myself that this is just an ice-breaking assignment for students who have never written any PHP before, or learned how to access command-line arguments, or convert strings to integers. That such a simple, context-free task is a nice way for them to succeed on their first effort. That our future assignments will be engaging, challenging, worthwhile. But... Ick.

The first time I teach a course, there always seem to be clunkers like this. Starting from scratch, relying on textbooks for inspiration, and working under time pressure all work against my goal of making everything students do in the class worth their time and energy. I suppose that problems such as this one are my opportunities to improve next time out.

My despair notwithstanding, I suspect that many students are happy enough to have at least one problem that is a gift, however uninteresting it may be. Maybe I can find solace in that while I'm working on exercises for my next problem set.


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

February 19, 2008 5:11 PM

Do We Need Folks With CS Degrees?

Are all the open jobs in computing that we keep hearing about going unfilled?

Actually -- they're not. Companies do fill those jobs. They fill them with less expensive workers, without computing degrees, and then train them to program.

Mark Guzdial is concerned that some American CEOs and legislators are unconcerned -- "So? Where's the problem?" -- and wonders how we make the case that degrees in CS matter.

I wonder if the US would be better off if we addressed a shortage of medical doctors by starting with less expensive workers, without medical degrees, and then trained them to practice medicine? We currently do face a shortage of medical professionals willing to practice in rural and underprivileged areas.

The analogy is not a perfect one, of course. A fair amount of the software we produce in the world is life-critical, but a lot is not. But I'm not sure whether we want to live in a world where our financial, commercial, communication, educational, and entertainment systems depend on software to run, and that software is written by folks with a shallow understanding of software and computing more generally.

Maybe an analogy to the law or education is more on-point. For example, would the US would be better off if we addressed a shortage of lawyers or teachers by starting with less expensive workers, without degrees in those areas, and then trained them? A shortage of lawyers -- ha! But there is indeed a critical shortage of teachers in many disciplines looming in the near future, especially in math and science. This might lead to an interesting conversation, because many folks advocate loosening the restrictions on professional training for folks who teach in our K-12 classrooms.

I do not mean to say that folks who are trained "on the job" to write software necessarily have a shallow understanding of software or programming. Much valuable learning occurs on the job, and there are many folks who believe strongly in a craftsmanship approach to developing developers. My friend and colleague Ken Auer built his company on the model of software apprenticeship. I think that our university system should adopt more of a project-based and apprenticeship-based approach to educating software developers. But I wonder about the practicality of a system that develops all of its programmers on the job. Maybe my view is colored by self-preservation, but I think there is an important role for university computing education.

Speaking of practicality, perhaps the best way to speak to the CEOs and legislators who doubt the value of academic CS degrees is in their language of supply and productivity. First, decentralized apprenticeship programs are probably how people really became programmers, but they operate on a small scale. A university program is able to operate on a slightly larger scale, producing more folks who are ready for apprenticeship in industry sooner than industry can grow them from scratch. Second, the best-prepared folks coming out of university programs are much more productive than the folks being retrained, at least while the brightest trainees catch. That lack of productivity is at best an opportunity cost, and at worst an invitation for another company to eat your lunch.

Of course, I also think that in the future more and more programmers will be scientists and engineers who have learned how to program. I'm inclined to think that these folks and the software world will be better off being educated by folks with a deep understanding of computing. Artists, too. And not only for immediately obvious economic reasons.


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

February 15, 2008 4:48 PM

Catching a Meme at the End of a Long Week

I don't usually play meme games in my web, but as I am winding down for the week I ran across this one on Brian Marick's blog: grab the nearest book, open it to page 123, go to the 5th sentence, and type up the three sentences beginning there.

With my mind worn out from a week in which I caught something worse than a meme, I fell prey and swung my arm around. The nearest book was Beautiful Code. Technically, I suppose that a stack of PHP textbooks is a couple of inches closer to me, but does anyone really want to know what is on Page 123 of any of them?

Here is the output:

The resultant index (which was called iSrc in FilterMethodCS) might be outside the bounds of the array. The following code loads an integer 0 on the stack and branches if iSrc is less than 0, effectively popping both operands from the stack. This is a partial equivalent of the if statement conditional in line 19 of Example 8-2:

Okay, that may not be much more interesting than what a PHP book might have to say, at least out of context. I'm a compiler junkie, though, and I was happy to find a compiler-style chapter in the book. So I turned to the beginning of the chapter, which turns out to be "On-the-Fly Code Generation for Image Processing" by Charles Petzold. I must admit that this sounds pretty interesting to me. The chapter opens with something that may be of interest to others, too:

Among the pearls of wisdom and wackiness chronicled in Steve Levy's classic "Hackers: Heroes of the Computer Revolution" (Doubleday), my favorite is this one by Bill Gosper, who once said, "Data is just a dumb kind of programming."

Petzold then goes on to discuss the interplay between code and data, which is something I've written about as one of the big ideas computer science has taught the world.

What a nice way for me to end the week. Now I have a new something to read over the weekend. Of course, I should probably spend most of my time with those PHP textbooks; that language is iteration 2 in my course this semester. But I've avoided "real work" for a lot less in the past.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

February 14, 2008 8:01 PM

Agile Thoughts While Preparing My Course

That is the title of a blog post that I planned to write five or six weeks ago. Here it is over a month later, and the course just ended. Well, it ended, and it begins again on Tuesday. So now I am thinking agile thoughts as I think back over my course, and still thinking agile thoughts as I prepare for the course. Let me explain.

810:151 is a different sort of course for us. We try to expose students to several different programming languages in the course of their undergraduate study. Even so, it is common for students to graduate thinking, "I wish I'd learned X." Sometimes X is a relatively new language, such as Scala or Groovy. Sometimes it's a language that is now more mainstream but has not yet made it into one of our courses, such as Ruby. Sometimes it is even a language we do emphasize in a course, such as Scheme, but in a course they didn't have an opportunity to take. We always have told students who express this wish that they should be well-equipped to learn a new language on their own, and they are. But...

While taking a full load of courses and working part-time (or taking a part-time load of courses and working full-time), it is often hard for students to set aside time to learn completely optional. People talk about "the real world" as if it is tougher than being in school, but students face a lot of competing demands for their time. Besides, isn't it often more fun to learn something from an expert who can help you learn the tricks of the trade faster and miss a few of the potholes that lie along the way?

I sometimes think of this course, which we call "Topics in Programming Languages", as a "make time" course for students who want to learn a new language, or perhaps a broader topic related to language, but who want or need the incentive that a regular course, assigned readings, and graded work provides. The support provided by the prof's guidance also is a good safety net for the less seasoned and less confident. For these folks, one of the desired outcomes is for them to realize, hey, I really can learn a language on my own.

We usually offer each section of 810:151 as a 1-credit course. The content reason is that the course has the relatively straightforward purpose of teaching a single language, without a lot of fluff. The practical purpose is that we can offer three 1-credit courses in place of a single 3-credit course. Rather than meet one hour per week for the entire semester, the course can meet 3 hours per week for 5 weeks. This works nicely for students who want to take all three, as they look and feel like a regular course. It also works nicely for students who choose to take only one or two of the courses, as they need not commit an entire semester's worth of attention to them.

This is my first semester assigned (by me) to teach this odd three-headed course. The topics this semester are Unix shell programming in bash, PHP, and Ruby.

I've been thinking of the three courses as three 5-week iterations. Though the topics of the three courses are different, they share a lot in terms of being focused on learning a language in five weeks. How much material can I cover in a course? How can students best use their time? How can I best evaluate their work and provide feedback? Teaching three iterations of a similar course in one semester is so much better for me when it comes to taking what I learn and trying to improve the next offering. With an ordinary course taught every semester, I would have to wait until next fall to begin implementing improvements; with an ordinary course three-course rotation, I would have to wait until Fall 2009!

I opted to dispense with all examinations and evaluate students solely in terms of the bash scripts they wrote. The goal of the course is for students to learn how to program in bash, so that is where I wanted the students' attention to be. One side effect of this decision is that the course is not really over yet; students will work on their final problem set in the coming week, and I'll have to grade it next Friday. The problem sets have consisted mostly in small-ish scripts that exercise the features of bash as we encounter them. We did have one larger task that students solved in three parts over the course of the semester, a processor for a Markdown-like mark-up language that produces HTML. This project scratched one of my own itches, as I like to use simple text-based, e-mail-friendly mark-up, and now I have a simple bash script that does the job!

One thing I did not do this semester that I thought I might, and which perhaps I should, is to work with them through a non-trivial shell script or two. I had thought that the fifth week would be devoted to examining and extending larger scripts, but I kept uncovering more techniques and ideas that I wanted them to see. Perhaps I could use a real script as a primary source for learning the many features of bash, instead of building their skills from the bottom up. That is how many of them have to come to know what little they know about shell scripting, by confronting a non-trivial script for building or configuring an open-source application that interests them. To be honest, though, I think that the bottom-up style that we used this semester may prepare them better for digging into a more complex script than starting with a large program first. This is one of the issues I hope to gain some insight into from student feedback on the course.

Making this "short iterations" more interesting is the fact that some students will be in all three of the iterations, but there will be a significant turnover in the class rosters. The client base evolves, but there should be enough overlap that I can get some comparative feedback as I try to implement improvements.

I tried to follow a few other agile principles as I started teaching this new prep. I tend to start each new course with a template from my past courses, from the way I organize sessions and lecture notes to the look-and-feel of the web site. This semester, I tried to maintain a YAGNI mindset: start as simple as I can, and add new elements only as I use them -- not when I think I need them tomorrow. By and large I have succeeded in this regard. My web site is bare-bones in comparison to my past sites, and lecture notes are plain text records of in-class activities and short messages to remind me and the students of what we discussed. I saved a lot of time not trying to produce attractive and complete lecture notes in HTML. Maybe some day, but this time around I just didn't need them.

One agile practice that I didn't think to encourage soon enough was unit testing. Shame on me. Some students suffered far more than I from this oversight. Many did a substandard job of testing their scripts, in part I think because they were biting off too much of a task to start. Unix pipelines are almost perfectly suited to unit testing, as one can test the heck out of each stage in isolation, growing the pipeline one stage at a time until the task is solved. The fact that each component is reading from stdin and writing to stdout means that later stages can be tested independent of the stages that precede it before we add it to the end.

For whatever reason, it didn't occur to me that there would exist an shUnit. It's too late for me to use it this semester, but I'll be sure to put phpUnit to good use in the next five weeks. And I've always known that I would use a unit testing framework such as this one for Ruby. Heck, we may even roll our own as we learn the language!

I've really enjoyed teaching a course with the Unix philosophy at the forefront of our minds. Simple components, the universal interface of plain text streams, and a mandate to make tools to work together -- the result is an amazingly "agile" programming environment. The best way to help students see the value of agile practices is to let them live in an environment where that is natural, and let them feel the difference from the programming environments in which they other times find themselves. I just hope that my course did the mindset justice.

The tool-builder philosophy that pervaded this course reminded me of this passage from Jason Marshall's Something to Say:

There's an old saying, "A good craftsman never blames his tools." Many people take this to mean "Don't make excuses," or even, "Real men don't whine when their tools break." But I take it to mean, "A good craftsperson does not abide inferior tools."

A good craftsman never blames his tools, because if his tools are blameworthy, he finds better tools. I associate this idea more directly with the pragmatic programmers than with the agile community, but it seems woven into the fabric of the agile approaches. The Agile Manifesto declares that we value "individuals and interactions over processes and tools", but I do not take this to mean that tools don't matter. I think it means that we should use tools (and processes) that empower us to focus our energy on people and interactions. We should let programs do what they do best so that we programmers can do what we do best. That's why we have unit testing frameworks, refactoring tools, automatic build tools, and the like. It's also why Unix is far more human-affirming than it is sometimes given credit for.

As I told students to close the lecture notes for this course: Don't settle for inferior tools. You are a computer programmer. Make the tools that make you better.


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

February 07, 2008 10:17 PM

Using the Writing Metaphor in Both Directions

I recently came across a SIGCSE paper from 1991 called Integrating Writing into Computer Science Courses, by Linda Hutz Pesante, who at the time was affiliated with the Software Engineering Institute at Carnegie Mellon. This paper describes both content and technique for teaching writing within a CS program, a topic that cycles back into the CS education community's radar every few years. (CS academics know that it is important even during trough periods, but their attention is on some other, also often cyclic, attention-getter.)

What caught my attention about Pesante's paper is that she tries help software engineers to use their engineering expertise to the task of writing technical prose. One of her other publications, a video, even has the enticing title, Applying Software Engineering Skills to Writing. I so often think about applying ideas from other disciplines to programming, the thought of applying ideas from software development to another discipline sounded like a new twist.

Pesante's advice on how to teach writing reflects common practice in teaching software development:

  • Motivate students so that they know what to expect.
  • Attend to the writing process, as well as the final product.
  • Use analogies to programming, such as debugging and code reviews.
  • Have students practice, and give them feedback.

Given Pesante's affiliation with the SEI, her suggestions for what to teach about writing made a bigger impression on me. The software engineering community certainly embraces a broad range of development "methodologies" and styles but, underlying its acceptance even of iterative methods, there seems to be a strong emphasis on planning and "getting things right" the first time.

Her content advice relies on the notion that "writing and software development have something in common", from user analysis through the writing itself to evaluation. As such, a novice writer can probably learn a lot from how programmers write code. Programmers like to be creative and explore when they write, too, but they also know that thinking about the development process can add structure to a potentially unbounded activity. They use tools to help them manage their growing base of documents and to track revisions over time. That part of the engineer's mindset can come in handy for writers. For the programmer who already has that mindset, applying it to the perhaps scary of writing prose can put the inexperienced writer at ease.

Pesante enumerates a few other key content points:

  • Writing takes place in a context.
  • The writing process is neither linear nor algorithmic.
  • The writing process is iterative.
  • Correct is not the same as effective.

The middle two of these especially feel more agile than the typical software engineering discussion. I think that the agile software community's emphasis on short iterations with frequent releases of working software to the client also matches quite nicely the last of the bullets. It's all too easy to do a good job of analysis and planning, produce a piece of software that is correct by the standards of the analysis and plan, and find that it does not meet the user's needs effectively. With user feedback every few weeks, the development team has many more opportunities to ensure that software stays on a trajectory toward effectiveness.

Most people readily accept the idea that creative writing is iterative, non-linear, and exploratory. But I have heard many technical writers and other writers of non-creative prose say that their writing also has these features -- that they often do not know what they had to say, or what their ultimate product would be, until they wrote it. My experience as a writer, however limited, supports the notion that almost all writing is exploratory, even when writing something so pedestrian as a help sheet for students using an IDE or other piece of software.

As a result, I am quite open to the notion that programming -- what many view as the creating of an "engineered" artifact -- also iterative, non-linear, and exploratory. This is true, I think, not only for what we actually call "exploratory programming" but also for more ordinary programming tasks, where both the client and I think we have a pretty good handle on what the resulting programming should do and look like. Often, over the course of writing an ever-larger program, our individual and shared understanding of the program evolves. Certainly my idea of the internal shape of the program -- the structure, the components, the code itself -- changes as the program grows. So I think that there is a lot to be learned going both directions in the writing:programming metaphor.


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

February 05, 2008 8:02 PM

What Steve Martin Can Teach Us

Steve Martin, on the beach

... about teaching, and about software development.

The February 2008 issue of Smithsonian Magazine contains an article called Being Funny, by comedian, writer, and actor Steve Martin, that has received a fair amount of discussion on-line already. When I read it this weekend, I was surprised by how similar some of the lessons Martin learned as he grew into a professional comedian are to lessons that software developers and teachers learn. I enjoyed being reminded of them.

I gave myself a rule [for dealing with the audience]. Never let them know I was bombing: this is funny, you just haven't gotten it yet.

This is about not showing doubt. Now, I think it's essential for an instructor to be honest -- something I wrote about a while back, in the context of comedy as well. So I don't mean that I as teacher should try to bluff my way through something I don't know or know but have botched. Martin is talking about the audience getting it, and the doubt that enters my mind when a classroom of students seem not to. I experience this occasionally when I teach a course like Programming Languages to a new group of students. Some classes don't warm to me or the material in quite the same way as others, but I know that the material I'm teaching and the basic approach I am using are sound. When this semester's crowd takes a while to catch on -- or if they are openly skeptical of the material or approach -- it's essential that I remain confident. Sure, I'll make adjustments to the presentation to account for my current students' needs, but I should remain steadfast: This is good stuff; they'll get it soon.

I'm not sure this applies as well for software developers. Often, when my users don't get it yet and I feel compelled to bull on through, I have gone beyond the requirements, at least as my users understand them. In those cases, it's usually better to say to myself "You aren't gonna need it" and simplify.

Everything was learned in practice, and the lonely road, with no critical eyes watching, was the place to dig up my boldest, or dumbest, ideas and put them onstage.

This is hard to do as a teacher. I don't get to go on the road to a hundred musty nightclubs and try out my new lecture on continuation-passing style, as Martin did with his bits. He was practicing on small stages in order to prepare for the big ones, such as The Tonight Show. It's next to impossible for me to try a lecture out on a representative audience that isn't my regular audience: my students. I can practice my research talks before a small local audience before taking them to a conference, but the number of repetitions available to me is rather small even in that scenario. For class sessions, I pretty much have to try them out live, see what happens, and feed the results back into my next performance.

Fortunately, I'm not often trying radically new ideas out in a lecture, so fewer and live repetitions may suffice. I have tried teaching methods that quite different than the norm for me and for my students, such as a Software Systems course or gen-ed capstone course with no lecture and all in-class exercises. In those scenarios, I had to follow the advice discussed above: This is going to work; they just haven't gotten it yet...

This piece of advice applies perfectly to programming. The lonely road is my office or my room at home, where I can try out every new idea that occurs to me by writing a program (or ten) and seeing how it works. No critical eyes but my eye, which I turn off. Bold ideas, dumb ideas -- I find out which are which through practice.

The consistent work enhanced my act. I learned a lesson: it was easy to be great. Every entertainer has a night when everything is clicking. These nights are accidental and statistical: like lucky cards in poker, you can count on them occurring over time. What was hard was to be good, consistently good, night after night, no matter what the circumstances.

This is so true of teaching that I have nothing more to say. Read Martin's line again.

I think this is also true of programming, and writing more generally. Every so often, a great idea comes to mind; a great turn of phrase; a cool little hack that solves the problem at hand. To be a good programmer, you need to practice, so that each time you sit down to code you can produce something of value. That kind of skill is earned by practice, and, I think, attainable by everyone.

On one of my appearances [on The Tonight Show, after [Johnny Carson] had done a solid impression of Goofy the cartoon dog, he leaned over to me during a commercial and whispered prophetically, "You'll use everything you ever knew."

When working with students, I find myself borrowing from every good teacher I've ever had, and drawing on any experience I can recall. I've borrowed standards and attitudes from one of my favorite undergrad profs, who taught me the value of meeting deadlines. I've used phrases and jokes spoken by my high school chemistry teacher, who showed us that studying a difficult subject could be fun, with the right mindset and a supportive group of classmates. Whatever works, works. Use it. Adapt it.

Likewise, this advice is true when programming. In the last few years, the notion of scrapheap programming has become quite popular. In this style, a programmer looks for old pieces of code that do part of the job at hand, adapts them, and glues them together to get the job done. But this is how all writers and programmers work, drawing on all of the old bits of code rolling around their heads. In addition to practice, you can improve as a programmer by exposing yourself to as many different programs as possible. That way, you will see the data structures, the idioms, the design patterns, and, yes, the snippets of code that you will use twenty years from now when the circumstance is right. That may seem goofy, but it's not.

Finally:

I believed it was important to be funny now, while the audience was watching, but it was also important to be funny later, when the audience was home and thinking about it.

As a teacher, I would like for what my students see, hear, and do in class today to make an impression today. That is what makes the material memorable and, besides, it's a lot more fun for both of us that way than the alternative. But perhaps more important, I would like for the ideas to make a lasting impression. When the student is home thinking about the course, or an assignment, or computer science in general, I want them to realize how much depth the idea or technique has, or breadth. Today's memorability can be ephemeral. When the idea sticks later, it can affect how the student programs forever.

The hard part is trusting when I don't see students getting it in real-time. Martin says that he learned not to worry if a gag got no response from his audience, "as long as I believed it had enough strangeness to linger". Strangeness may not be what I hope for in my class sessions, but I know what he means.

As a programmer, I think this advice applies, too. When I was an undergrad, I was once on a team building a large system as part of our senior project course. One of our teammates loved to write code that was clever, that would catch our eye on first read and recognize his creativity and skill. But we soon learned that much of this code was inscrutable in a day or two, which made modifying and maintaining his modules impossible. Design and code that makes a module easy to read and understand in a few weeks are what the team needed. Sometimes, the cleverness of a solution shone through then, too, but it impressed us all the more when it had "staying power".

Steve Martin is wacky comedian, not a programmer or teacher per se. Does his advice apply only in that context? I don't think so. Comedians are writers and creators, and many of the traits that make them successful apply to other tasks that require creating and communicating.


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

February 04, 2008 6:51 AM

The Program's the Thing

Readers of this blog know that programming is one of the topics I most like to write about. In recent months I've had something of a "programming for everyone" theme, with programming as a medium of expression, as a way to create new forms, ideas, and solutions. But programming is also for computer scientists, being the primary mode for communicating their ideas.

To the non-CS folks reading this, that may seem odd. Isn't CS about programming? Most non-CS folks seem to take as a given that computer science is, but these days it is de rigeur for us in the discipline to talk about "computing" and how much bigger it is than "just programming".

Too some extent, I am guilty of this myself. I often use the term "computing" generically in this blog to refer to the fuzzy union of computer science, software engineering, applications, and related disciplines. This term allows me to talk about issues in their broadest context without limiting my focus to any one sub-discipline. But it also lets me be fuzzy in my writing, by not requiring that I commit.

Sometimes, that breadth can give the impression that I think programming is but a small part of the discipline. But most of my writing comes back to programming, and when I teach a CS course, programming is always central. When I teach introductory computer science, programming is a way for us to explore ideas. When I teach compilers, it all comes down to the project. My students learn Programming Languages and Paradigms by writing code in a new style and then using what they learn to explore basic ideas about language in code. When I taught AI for eight or ten straight years, as many of the big ideas as possible found their way into lab exercises. Even when I taught one course that had no programming component -- an amalgam of design, HCI, and professional responsibility called Software Systems -- I had students read code: simple implementations of model-view-controller, written in Java, C++, Common Lisp, or Ada!

I love to program, and I hope students leave my courses seeing that programming is medium for expressing and creating ideas -- as well as creating "business solutions", which will be the professional focus for most of them. Then again, the best business solutions are themselves ideas that need to be discovered, explored, and evolved. Programming is the perfect medium to do that.

So when I ran across The Nerd Factor is Huge, via Chuck Hoffman at Nothing Happens, I found myself to be part of the choir, shouting out "Amen, brother!" every so often. The article is a paean to programming, in a blog "dedicated to the glory of software programming". It claims that programming needs an academic home, a discipline focused on understanding it better and teaching people how to do it. (And that discipline should have its own conference!)

In Yegge-like fashion, the author uses expressive prose to makes big claims, controversial claims. I agree with many of them, and feel a little in harmony even with the ones I wouldn't likely stake my professional reputation on.

  • The shortage of women in computer science hurts our discipline, and it limits the opportunities available to the women, both intellectual and economic. I would broaden this statement to include other underrepresented groups.

  • Trying to interest girls and other underrepresented groups by "expanding the non-programming ghettos of computer science" is misguided and insults these people. We can certainly do more to communicate how becoming a computer scientist or programmer empowers a person to effect change and produce ideas that help people, but we should not remove from the equation the skill that makes all that possible.

  • Human-computer interaction doesn't belong in computer science. Doing so "is as insulting to the study of interaction design ... as it is to computer science". This is perhaps the most controversial claim in this paper, but the authors makes clear that he is not showing to disrespect to HCI. Instead, he wants due respect shown to it -- and programming, which tends to get lost in a computer science that seeks to be too many things.

I agree with the central thesis of this article. However, separating programming as a discipline from HCI and some of the other "non-programming ghettos" of CS creates a challenge for university educators. Most students come to us not only for enlightenment and great ideas but also for professional preparation. With several distinct disciplines involved, we need to help students put them all together to prepare them to be well-rounded pros.

How should we encourage more kids -- girls and boys alike -- to study computer science? "Nerd Factor" is right: don't shy away from programming; teach it, and sooner rather than later. Show them "how easy it is to create something. Because that is what programming is all about: making things." And making things is the key. Being able to program gives anyone the power to turn ideas into reality.

One of my early memories of OOPSLA comes from a panel discussion. I don't recall the reason for the panel, but several big names were talking about what we should call people who create software. There were probably some folks who supported the term "software engineer", because there always are. Kent Beck spoke heresy: "I'm just a programmer." I hope I muttered a little "Amen, brother" under my breath that day, too.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

February 01, 2008 8:57 AM

An Unexpected Connection

I wasn't expecting to hear John Maeda's name during the What is a Tree? talk, because I didn't know that researchers in Maeda's lab had created the language Processing. But hearing his name brought to mind something that has been in the back of my mind for a couple of months, since the close of my first theater experience. I had blogged about a few observations my mind had made about the processes of acting in and directing a play. The former were mostly introspective, and the latter were mostly external, as I watched our director coalesce what seemed like a mess into a half-way decent show. Some of these connections involved similarities I noticed between producing a play and creating software.

I made notes of a few more ideas that I hadn't mentioned yet, including:

  • "Release time" is chaos. Even with all of the practice and rehearsal, the hours before the show on opening night were a hectic time, worrisome for a few and distracting for others.
  • You hope for perfection, but there will mistakes. Just do it.
  • No matter what happens on stage or off, when you are on stage, you must stay in character. You are not yourself playing a character; you are the character.
  • As a novice player, I struggled throughout, even to the last call of the final show, with self-consciousness on stage. I think that unself-consciousness -- detachment -- is a skill that can be developed with practice. I need more.

I'm still wondering if those last two have any useful analogue in software development...

Since the show ended, I have occasionally tried to discern the value in the analogy between producing a play and creating software -- indeed, if there is any. That's where the connection to Maeda comes in. Last summer, I read the slender Laws of Simplicity, a collection of essays from Maeda's blog of the same name. The book suggest ten ways that we can design simpler systems and products. I must not have been in the right place to read the book just then, because I didn't get as much out of it as I had hoped. But one part of the book stuck with me.

For a metaphor to engage us deeply, Maeda wrote, it is essential that it relate, translate, and surprise. As I recall now, this means that the metaphor must relate the elements of the two things, that it must translate foreign elements from one of the things to the other, and that the result of this translation should surprise -- it should make us see or understand the other thing in a new way, give us insight.

There is a danger in finding analogies everywhere we look by making superficial connections. I am perhaps more prone to this risk than many other folks. That may be why I liked Maeda's relate/translate/surprise triad so much. Since reading it, I have used it as an external checkpoint for any new analogy that I want to make. If I can explain how the metaphor relates the two things, translates disparate elements, and surprises me, then I have some reason to think that the metaphor offers value -- at least more reason than just saying, "Hey, look at this cool new thing I noticed!"

To this point, I have not found the "surprise" in the theater experience that teaches me something new about how to think about making software. This doesn't mean that there is no value in the analogy, only that I haven't found it yet. By remaining skeptical a little while longer, I decrease the probability that I try to draw an inappropriate conclusion from the relationship.

Of course, just because I haven't yet found the surprise in the analogy doesn't mean that I did not find value in the experience that led me to it. A rich web of experiences is valuable in its own right, and enjoyable. It also provides the source material for learning.


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

January 29, 2008 4:20 PM

A Broken Record?

Last night I attended a meeting with several CS colleagues, colleagues from Physics and Industrial Technology, representatives from the local company DISTek Integration, and representatives from National Instruments, which produces the programming environment LabVIEW. Part of the meeting was about LabVIEW and how students and faculty at my school use it. Our CS department does not use it at all, which is typical; the physicists and technologists use it to create apps for data acquisition and machine control.

Most of the meeting was much more interesting than tool talk and sales pitch, because it was about how to excite more kids and university students about IT careers and programming, and about how LabVIEW users work. Most of the folks who program in LabVIEW at DISTek are test engineers, not trained software developers. But the programming environment makes it possible for them to build surprisingly complex applications. As they grow their apps, and attack bigger problems because they can, the programs become unwieldy and become increasingly difficult to maintain and extend.

It turns out that program design matters. It turns out that software architecture matters. But these programmers aren't trained in the writing software, and so they do much of their work with little or no understanding of how to structure their code, or refactor it into something more manageable.

These folks are engineers, not scientists, but I felt a deep sense of deja vu. Our conversations sounded a lot like what we discussed with physicists at the SECANT workshop to which I keep referring.

I think we have a great opportunity to work with the folks at DISTek to help their domain-specific programmers learn the software development skills they need to become more effective programmers. Working with them will require us to think about how to teach a focused software development curriculum for non-programmers. I think that this will be work worth doing as we encounter more and more folks, in more and diverse domains, who need that sort of software development education -- not a major or maybe even minor in CS -- in order to do what they do.


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

January 25, 2008 2:07 PM

Running, Programming, and Tools

I enjoyed a brisk 5-mile run outdoors yesterday morning. That isn't much to write about, except that yesterday morning the temperature dipped to an all-time record low for January 24 here, bottoming out at -29° Fahrenheit. (All together now: Here's your sign.) At least the wind didn't make it feel much colder than that.

The thing is, I did enjoy the run. I stayed plenty warm, thanks to my clothing and the physical act of running. First, I threw on a layer or two more than usual. Second, my wife gave me a couple of pieces of new gear for Christmas: a pair of fleece running mittens with a second, wind-resistant outer layer, and an ultra-warm headband that I wore under my usual thermal hat. My fingers and toes have always been my weak spot in the cold, and for the first time ever in very cold weather, my fingers didn't get cold at all. My attire did the job, and the new gear worked just as I had hoped.

In running, as in programming, good tools make all the difference. I really liked Jason Marshall's take on this in a recent Something to Say:

There's an old saying, "A good craftsman never blames his tools." Many people take this to mean "Don't make excuses," or even, "Real men don't whine when their tools break." But I take it to mean, "A good craftsperson does not abide inferior tools."

I'm teaching a course on Unix shell scripting the first five weeks of this semester, and tool-building is central to the Unix philosophy. I hope that students see that they never have to abide inferior tools, or even okay tools that do not meet their needs. With primitive Unix commands, pipelines, I/O redirection, a little sed and awk, and the more general programming language of bash, they can do so much to customize their environment so that it meets their needs. If the shell isn't enough, they can use a general-purpose programming language. Progress depends on the creation of better tools.

I like to build software tools for myself. I'm not equipped to make my own running gear, though, and being, um, careful with my money means that I am sometimes slow to buy the more expensive item. But after running 7500 miles over the last four years, I've slowly realized that I'm enough of a runner to use better gear. A few experiences like yesterday morning's make it easier to purchase the right equipment for the job. Learning shell scripting, or a better programming language, can have the same effect on a programmer.


Posted by Eugene Wallingford | Permalink | Categories: Running, Software Development

January 24, 2008 6:39 AM

More on Computational Simulation, Programming, and the Scientific Method

As I was running through some very cold, snow-covered streets, it occurred to me that my recent post on James Quirk's AMRITA system neglected to highlight one of the more interesting elements of Quirk's discussion: Computational scientists have little or no incentive to become better programmers, because research papers are the currency of their disciplines. Publications earn tenure and promotion, not to mention street cred in the profession. Code is viewed by most as merely a means to an end, an ephemeral product on the way to a citation.

What I take from Quirk's paper is that code isn't -- or shouldn't be -- ephemeral, or only a means to an end. It is the experiment and the source of data on which scientific claims rest. As I thought more about the paper I began to wonder, can computational scientists do better science if they become better programmers? Even more to the point, will it become essential for a computational scientist to be a good programmer just to do the science of the future? That's certainly what I heard some of the scientists at the SECANT workshop saying.

While googling to find a link to Quirk's article for my entry (Google is the new grep. TM), I found the paper Computational Simulations and the Scientific Method (pdf), by Bil Kleb and Bill Wood. They take the programming-and-science angle in a neat software direction, suggesting that

  • the creators of a new simulation technique should publish unit tests that specify the technique's intended behavior, and
  • the developers of scientific simulation code for a given technique use its unit tests to demonstrate that their component correctly implements the technique.

Publishing a test fixture offers several potential benefits, including:

  • a way to communicate a technique or algorithm better
  • a way to share the required functionality and performance features of an implementation
  • a way to improve repeatability of computational experiments, by ensuring that scientists using the same technique are actually getting the same output from their component modules
  • a way to improve comparison of different experiments
  • a way to improve verification and validation of experiments

These are not about programming or software development; they are about a way to do science.

This is a really neat connection between (agile) software development and doing science. The idea is not necessarily new to folks in the agile software community. Some of these folks speak of test-driven development in terms of being a "more scientific" way to write code, and agile developers of all flavors believe deeply in the observation/feedback cycle. But I didn't know that computational scientists were talking this way, too.

After reading the Kleb and Wood paper, I was not surprised to learn that Bil has been involved in the Agile 200? conferences over the years. I somehow missed the 2003 IEEE Software article that he and Wood co-wrote on P and scientific research and so now have something new to read.

I really like the way that Quirk and Kleb & Wood talk about communication and its role in the practice of science. It's refreshing and heartening.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

January 22, 2008 4:37 PM

Busy Days, Computational Science

Some days, I want to write but don't have anything to say. The start of the semester often finds me too busy doing things to do anything else. Plowing through the arcane details of Unix basic regular expressions that I tend not to use very often is perhaps the most interesting thing I've been doing.

Over the weekend, I did have a chance to read this paper by James Quirk, a computational scientist who has built a sophisticated simulation-and-documentation system called AMRITA. (You can download the paper as a PDF from his web site, by following About AMRITA and clinking on the link "Computational Science: Same Old Silence, Same Old Mistakes".) Quirk's system supports a writing style that interleaves code and commentary in the spirit of literate programming using the concept of a program fold, which at one level is a way to specify a different processor for each item in a tree of structured text items. The AMRITA project is an ambitious mixture of (1) demonstrating a new way to communicate computational science results and (2) arguing for software standards that make it possible for computational scientists to examine one another's work effectively. The latter point is essential if computational science is to behave like science, yet the complexity of most simulation programs almost precludes examination, replication, and experimentation with the ideas they implement.

Much of what Quirk says about scientists as programmers meshes with what I wrote in my reports on November's SECANT workshop. The paragraph that made me sit up, though, was this lead-in to his argument:

The AMR simulation shown in Figure 1 was computed July 1990.... It took just over 12 hours to run on a Sun SPARCstation 1. In 2003 it can be run on an IBM T30 laptop in a shade over two minutes.

It is sobering occasionally to see the advances in processors and other hardware presented in such concrete terms. I remember programming on a Sun SPARCstation 1 back in the early '90s, and how fast it seemed! By 2003 a laptop could perform more than 300 times faster on a data-intensive numeric simulation. How much faster still by 2008?

Quirk is interested in what this means for the conduct of computational science. "What should the computational science community be doing over and above scaling up the sizes of the problems it computes?" That is the heart of his paper, and much of the motivation behind AMRITA.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

January 16, 2008 12:02 PM

An Open-Source Repository for Course Projects

I don't write many entries for the purpose of passing on a link, but I am making an exception for the Repository for Open Software Education (ROSE), being hosted by a group at North Carolina State University that includes Laurie Williams. You know I am a big fan of project-based courses, and one of the major impediments to faculty teaching courses this way is creating suitable projects. For example, every time I teach compilers, I face the task of choosing or creating a programming language for students to use as their source. I like to use a language that is at least a little different than languages I've used in the past, for a couple of reasons, and that is hard work.

For more generic project courses in software engineering, the problem is compounded by the fact that you may want your students to work on an existing system, so that they can encounter issues raised by a larger system than they might write from scratch themselves. But where will such large software come from? Sites like SourceForge offer plenty of systems, but they come at so many levels of completeness, complexity, documentation, and accessibility. Finding projects suitable for a one-semester undergraduate course in the morass is daunting.

ROSE aims to host open-source projects that are of suitable scope and can grow slowly as different project teams extend them. Being targeted at educators, the repository aims to record information about requirements, design, and testing that are often missing or inscrutable in other open-source projects. At this point, ROSE contains only one project larger than 5K lines of code, but that will change as others contribute their projects to the repository.

As Laurie noted in her announcement of ROSE, for a few years now the CS education community has had a Nifty Assignments repository, which offers instructors a set of fun, challenging, and battle-tested programming assignments to use in lower-division courses. ROSE will host larger open-source projects for use in a variety of ways. It is a welcome addition.


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

January 14, 2008 2:25 PM

Planning and the Project Course

After "worrying out loud" in a recent entry, I suppose I should report that our faculty retreat went well. We talked about several different across over the course of the day, especially long-term goals, outcomes assessment, and tactics for the next few months. The biggest part of our goals discussion related to broadening our reach to more students who are not and may never want to be CS majors. That includes science majors but also social science, business, humanities, and education students.

While discussing how to determine whether or not our courses and programs of study were accomplishing what we want them to accomplish, we had what was in many ways the most interesting discussion of the day. It dealt with our "capstone" project course.

In all of the CS majors we offer, each student is required to complete a "project course" in one of the areas of study we offer. This will be the third course the student takes in that area, which is one way that we try to require students to gain some depth in at least one area of computing. When we added this requirement to our programs, the primary goal was to give students a chance to work in teams on a large piece of software, something bigger than they'd worked on in previous courses and bigger than one person could complete alone.

Some of our project courses are "content-heavy", in that they introduce new topical content while students are working on the project. The compilers course is an example of such a course; "Real-Time Embedded Systems" is another. Others do not introduce much new content and focus on the team project experience. "Projects in Systems" (for the OS/networking crowd) and "Projects in Information Science" (for the database/IR crowd) are examples. Over the years, as we've broadened our faculty and the areas we teach, we've added new project courses to the broaden the type of experience offered as well. In some of these courses, code is not the primary deliverable. For example, in "Software Testing", students might develop a testing environment, a suite of test plans, and documentation; in "User Interface Design", students focus on developing a front end to an existing system or to a lighter proof-of-concept back end that they write. Some of these courses implement looser versions of the original idea in other ways, too. My compiler students usually work in pairs or threes, rather than the four or five that we imagined we designed this part of the curriculum over a decade ago.

Our outcomes assessment discussion turned quickly to the nature of a project course and in particular the diversity we now offer under this banner. We can't write outcomes for the project requirement that refer to code as a primary deliverable if, in fact, several courses do not require that of students. Well, we could, but then we would have to change how we teach the courses -- perhaps drastically. The question was, is code an essential outcome of this part of our curriculum?

We faced similar questions as we explored the other elements of diversity. How much new content should a project introduce? Must students write prose, in the form of documentation, etc.? Should they give oral presentations? If so, should these be public, or is an internal presentation to the class or instructor sufficient? What about the structured demos that our interface design students give as a part of an end-of-the-term open house?

I enjoyed listening to all of my colleagues describe their courses in more detail than I had heard in a while. After our discussion, we decided for the most part to preserve the rich ecology of our project course landscape. Test plans and UIs are okay in place of code in certain courses; the essential outcome is that students be expected to produce multiple deliverables across the life of the project. We also found some common themes that we could agree on, even if it meant tweaking our courses. For example, whatever kind of presentation our students give at the end of the project, it should be open to the public and allow public questioning. We will be writing these outcomes up more formally as we proceed this semester and use them as we evaluate the efficacy of our curriculum.

I was impressed with the diversity of ideas in practice in our project courses. Perhaps the results of this discussion were interesting mostly because we have had this sort of conversation in a long time, at least not as a whole faculty. It's funny, but "shared knowledge" isn't always what we think it is. Sometimes we don't share as much as we think we do, at least of the surface. When we dig deeper, we can find common themes and also fundamental differences, which we can then explore explicitly and in the context of the shared knowledge. It was neat to see how each of us learned a little something new about the goals of the project course and left the conversation with an idea for improving our own courses. My compiler students certainly don't write enough technical prose in my course, certainly not as much or as structured as students in some of the other project courses. I can make my course stronger, and more consistent with the other options, by changing how I teach the course next time, and what I require of the class.

Our retreat didn't answer all my questions about the direction of the department or our strategic and tactical plans. Only in the fantasy of a manager could it! My job now is to take what we learned and decided about ourselves that day, help craft from that a coherent plan of action for the department, and begin to take concrete actions to move us in the direction we want to go. I hope that, as in most other endeavors, we will do some things, learn from the feedback, and adjust course as we go.


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

December 21, 2007 4:05 PM

A Panoply of Languages

As we wind down into Christmas break, I have been thinking about a lot of different languages.

First, this has been a week of anniversaries. We celebrated the 20th anniversary of Perl (well, as much as that is a cause for celebration). And BBC World ran a program celebrating the 50th birthday of Fortran, in the same year that we lost John Backus, its creator.

Second, I am looking forward to my spring teaching assignment. Rather than teaching one 3-credit course, I will be teaching three 1-credit courses. Our 810:151 course introduces our upper-division students to languages that they may not encounter in their other courses. In some departments, students see a smorgasbord of languages in the Programming Languages course, but we use an interpreter-building approach to teach language principles in that course. (We do expose them in that course to functional programming in Scheme, but more deeply.)

I like what that way of teaching Programming Languages, but I also miss the experience of exposing students to the beauty of several different languages. In the spring, I'll be teaching five-week modules on Unix shell programming, PHP, and Ruby. Shell scripting and especially Ruby are favorites of mine, but I've never had a chance to teach them. PHP was thrown in because we thought students interested in web development might be interested. These courses will be built around small and medium-sized projects that explore the power and shortcomings of each language. This will be fun for me!

As a result, I've been looking through a lot of books, both to recommend to students and to find good examples. I even did something I don't do often enough... I bought a book, Brian Marick's Everyday Scripting with Ruby. Publishers send exam copies to instructors who use a text in a course, and I'm sent many, many others to examine for course adoption. In this case, though, I really wanted the book for myself, irrespective of using it in a course, so I decided to support the author and publisher with my own dollars.

Steve Yegge got me to thinking about languages, too, in one of his recent articles. The article is about the pitfalls of large code bases but, while I may have something to say about that topic in the future, what jumped out to me while reading this week were two passages on programming languages. One mentioned Ruby:

Java programmers often wonder why Martin Fowler "left" Java to go to Ruby. Although I don't know Martin, I think it's safe to speculate that "something bad" happened to him while using Java. Amusingly (for everyone except perhaps Martin himself), I think that his "something bad" may well have been the act of creating the book Refactoring, which showed Java programmers how to make their closets bigger and more organized, while showing Martin that he really wanted more stuff in a nice, comfortable, closet-sized closet.

For all I know, Yegge's speculation is spot on, but I think it's safe to speculate that he is one of the better fantasy writers in the technical world these days. His fantasies usually have a point worth thinking about, though, even when they are wrong.

This is actually the best piece of language advice in the article, taken at its most general level and not a slam at Java in particular:

But you should take anything a "Java programmer" tells you with a hefty grain of salt, because an "X programmer", for any value of X, is a weak player. You have to cross-train to be a decent athlete these days. Programmers need to be fluent in multiple languages with fundamentally different "character" before they can make truly informed design decisions.

We tell our students that all the time, and it's one of the reasons I'm looking forward to three 5-week courses in the spring. I get to help a small group of our undergrads crosstrain, to stretch their language and project muscles in new directions. That one of the courses helps them to master a basic tool and another exposes then to one of the more expressive and powerful languages in current use is almost a bonus for me.

Finally, I'm feeling the itch -- sometimes felt as a need, other times purely as desire -- to upgrade the tool I use to do my blogging. Should I really upgrade, to a newer version of my current software? (v3.3 >> v2.8...) Should I hack my own upgrade? (It is 100% shell script...) Should I roll my own, just for the fun of it? (Ruby would be perfect...) Language choices abound.

Merry Christmas!


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

December 20, 2007 11:30 AM

Increasing Your Sustainable Pace

Sustainable pace is part of the fabric of agile methods. The principles behind the Agile Manifesto include:

Agile processes promote sustainable development. The sponsors, developers, and users should be able to maintain a constant pace indefinitely.

When I hear people talk about sustainable pace, they are usually discussing time -- how many hours per week a healthy developer and a healthy team can produce value in their software. The human mind and body can work so hard for only so long, and trying to work hard for longer leads to problems, as well as decline in productivity.

The first edition of XP had a practice called 40-hour work week that embodied this notion. The practice was later renamed sustainable pace to reflect that 40 hours is an arbitrary and often unrealistic limit. (Most university faculty certainly don't stop at 40 hours. By self-report at my school, the average work week is in the low-50s.) But the principle is the same.

Does this mean that we cannot become more productive?

Recall that pace -- rate -- is a function of two variables:

rate = distance / time

Productivity is like distance. One way to cover more distance is to put in more time. Another is to increase the amount of work you can do in a given period of time.

This is an idea close to the heart of runners. While I have written against running all out, all the time, I know that the motivation found in that mantra is to get faster. Interval training, fartleks, hill work, and sustained fast pace on long runs are all intended to help a runner get stronger and faster.

How can software developers "get faster"? I think that one answer lies in the tools they use.

When I use a testing framework and automate my tests, I am able to work faster, because I am not spending time running tests by hand. When I use a build tool, I am able to work faster, because I am not spending time recompiling files and managing build dependencies. When I use a powerful -- and programmable -- editing tool, whether it is Eclipse or Emacs, I am able to work faster, because I am not spending time putzing around for the sake of the tool.

And, yes, when I use a more powerful programming language, I am able to work faster, because I am not spending time expressing thoughts in the low-level terms of a language that limits my code.

So, programmers can increase their sustainable pace by learning tools that make them more productive. They can learn more about the tools they already use. They can extend their tools to do more. And they can write new tools when existing tools aren't good enough.

Perhaps it is not surprising that I had this thought while running a pace that I can't sustain for more than a few miles right now. But I hope in a few months that a half marathon at this pace will be comfortable!


Posted by Eugene Wallingford | Permalink | Categories: Running, Software Development

December 10, 2007 1:19 PM

It's a Wrap

My first run as an actor has ended without a Broadway call. Nonetheless I consider it to have been successful enough. My character didn't cause any major interruptions in the flow of our three performances, and I even got us back on track a time or two. Performing in front of a crowd -- especially a crowd that contained personal friends -- was enough different from giving a lecture or speaking in public that it wracked a few nerves. But getting a laugh from a real audience was also enough different from a laugh in a lecture, too, and the buzz could feed the rest of the performance.

My first post on this topic recorded dome thoughts I had had on the relationship between developing software and directing a play. In those thoughts, the director or producer is cast as the software developer, or vice versa. In the last couple of weeks, my thoughts turned more often to my role as performer. Here are a few:

  • Before each rehearsal and performance, I found myself spending important minutes setting up my environment: making sure props were in place, adjusting positions based on any results from the last time, and finding a place backstage for my time between scenes. This felt a lot like how I set up for time writing code, getting my tools in place.

  • I wonder if there is any analogue in software development the self-consciousness I felt as I began to perform on stage? Over time, the director helped me to morph some of the self-consciousness into a sensitivity to the scene and my fellow players.

    After a while, experience helps push self-consciousness into the background. It was even possible to get into a flow where the self disappeared for a moment. I think I need more experience in character to have more experiences like that! But those moments were special.

  • Once we got into performances, I noticed a need for the same almost contradictory combination of hubris and humility that a programmer needs. At some point, I had to know my lines and scenes so well that I could nail them blind. That drove a form of confidence that let me "own" my character in a scene. Yet I had to be careful not to become too cocky, because suddenly something would go wrong and I'd find myself exposed and not at all in control. So I spent a few minutes before every scene preparing, just refreshing my memory of cues and placements and notes the director had given. That bit of humility gave me more confidence than I otherwise could have had.

Most of the relationships I noticed between acting in the play and building software were really patterns of good teams. In every scene I depended upon the presence and performance of others -- and they depended on me. Being a good teammate mattered both on stage (while performing) and off (when preparing and when taking and giving feedback). "The key to acting," said our director, "is listening to other people." Funny how that is the key to so many things.

As I look back on this (first?) experience being a player in a stage production, I think that there is a lot to this notion that developing software is like producing a play -- and that producing a play is like developing software. The two media are so different, but they are both malleable, and both ultimately depend on their audiences (users).

Over the course of two weeks or so, the director did a lot of what I call refactoring. For example, he found the equivalent of duplicated code -- lines and even larger parts of scenes that don't move the story forward, given how the rest of the play is being staged. Removing duplicated stuff frees up stage real estate and time for making other additions and changes. He also aggressively sought and deleted dead space -- moments when no one was on stage (say, in the transition between scenes) or no active was taking place (say, when lighting changed). Dead space kills the energy of the show and distracts the viewer. Dead space is a little like dead code and over-designed code -- code that isn't contributing to the application. Cut it.

Every night after rehearsal and even shows, the director "ran notes" with us. This was a time after each "iteration" dedicated to debugging and refactoring. That's good practice in software.

One other connection jumped out to me yesterday. After we closed the show, I was chatting with Scott Smith, a local filmmaker whose is real-life husband to the woman who played my wife in the show. We were discussing how filmmaking has changed in the last decade or so. In the not-so-old days folks in video were strongly encouraged to become specialists in one of the stages: writing, directing, shooting, editing, and so on. Now, with the wide availability of relatively inexpensive equipment and digital tools, and economic pressures to deliver more complete services, even veterans such as Smith find themselves developing skills across the board, becoming not a jack-of-all-trades but master of none, but rather strong in all phases of the game.

I immediately thought of extreme programming's rapid development cycle that requires programmers to be not only writers of code but also writers of stories and tests, to be able to interact with clients and to grow designs and architectures. It's hard to be a master of all trades, but the sort of move we have seen in software and in filmmaking from specialist to generalist encourages a deep competence in all areas. Too often I have heard folks say "I am a generalist" as way to explain their lack of expertise in any one area. But the new generalist is competent across the board, perhaps expert in multiple areas, and able to contribute meaningful to the whole lifecycle.

One last idea. Just before our final show, the director gave us our daily pep talk. He said that come performers view the last show as occasion to do something wacky -- to misplace someone's prop, or deliver a crazy line not from the script, or to affect some voice or mannerism on stage. That sounds like fun, he said, but remember: For the audience out in the seats today, this is the first show. They deserve to see the best version of the show that we can give. For some reason, I thought of software developers and users. Maybe my mind was just hyperactive at that moment when we were about to create our illusion. Maybe not.


Posted by Eugene Wallingford | Permalink | Categories: Personal, Software Development

November 29, 2007 4:38 PM

Coincidence by Metaphor

I recently wrote that I will be in a play this Christmas season. I'm also excited to have been asked by Brian Marick to serve on a committee for the Agile2008 conference, which takes me in another direction with the performance metaphor. As much as I write about agile methods in my software development entries, I have never been to one of the agile conferences. Well, at least not since they split off from OOPSLA and took on their own identity.

Rather than using the traditional and rather tired notion of "tracks", Agile2008 is organized around the idea of stages, using the metaphor of a music festival. Each stage is designed and organized by a stage producer, a passionate expert, to attract an audience with some common interest. In the track-based metaphor -- a railroad? -- such stages are imposed over the tracks in much the way that aspects cut across the classes in an object-oriented program.

(At a big conference like OOPSLA, defining and promoting the crosscutting themes is always a tough chore. Now that I have made this analogy, I wonder if we could use ideas from aspect-oriented programming to do the job better? Think, think.)

I look forward to seeing how this new metaphor plays out. In many important ways, the typical conference tracks (technical papers, tutorials, workshops, etc.) are implementation details that help the conference organizers do their job but that interfere with the conference participants' ability to access events that interest them. Why not turn the process inside out and focus on our users for a change? Good question!

(Stray connection: This reminds of an interview I heard recently with comedian Steve Martin, who has written a biography of himself. He described how he developed his own style as a stand-up comedian. Most comedians in that era were driven by the punch line -- tell a joke that gets you to a punch line, and then move on to the next. While taking a philosophy course, he learned that one should question even the things that no one ever questioned, what was taken for granted. What would be comedy be like without a punch line? Good question!)

Of course, this changes how the conference organizers work. First of all, it seems that for a given stage the form of activity being proposed could be almost anything: a presentation, a small workshop, a demonstration, a longer tutorial, a roundtable, ... That could be fun for the producers and their minions, and give them some much needed flexibility that is often missing. (Several times in the past I have had to be part of rejecting, say, a tutorial when we might gladly have accepted the submission if reformulated as a workshop -- but we were the tutorials committee!)

Brian tells me that Agile 2008 will try a different sort of submission/review/acceptance process. Submissions will be posted on the open web, and anyone will be able to comment on them. The review period will last several months, during which time submitters can revise their submissions. If the producer and the assistant producers participate actively in reviewing submissions over the whole period, they well put in more work than in a traditional review process (and certainly over a longer period of time.) But the result should be better submissions, shaped by ideas from all comers -- including potential members of the audience that the stage hopes to attract! -- and so better events and a better conference. It will be cool to be part of this experiment.

the Agile 2008 Examples stage logo

As you can see from the Agile 2008 web site, its stages correspond to themes, not event formats. Brian is producing a stage called "Designing, Testing, and Thinking with Examples", the logo for which you see here. This is an interesting theme that goes beyond particular behaviors such as designing, testing, and teaching to the heart of a way to think about all of them, in terms of concrete examples. The stage will not only accept examples for presentation, demonstration, or discussion, but glory in them. That word conveys the passion that Brian and his assistant producer Adam Geras bring to this theme.

I think Brian asked me to help them select the acts for this stage because I have exhibited some strong opinions about the role of examples and problems in teaching students to program and to learn the rest of computer science. I'm pretty laid back by nature, and so don't often think of myself in terms of passion, but I guess I do share some of the passion for examples that Brian and Adam bring to the stage. This is a great opportunity for me to broaden my thinking about examples and to see what they means for the role they play in my usual arenas.

In a stroke of wisdom, no one has asked me yet to be on the stage, unlike my local director friend. Whatever practice I get channeling Jackson Davies, I am not sure I will be ready for prime time on the bright lights of an Agile stage...

It occurs to me that, following this metaphor one more step, I am not playing the role of a contestant on, say, American Idol, but the role of talent judge. Shall I play Simon or Paula? (Straight up!)


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

November 28, 2007 3:33 PM

Learning About Software from The Theater, and Vice Versa

Last Sunday was my fourth rehearsal as a newly-minted actor. It was our first run-through of the entire play on stage, and the first time the director had a chance to give notes to the entire cast. The whole afternoon, my mind was making connections between plays and programs -- and I don't mean the playbill. These thoughts follow from my experiences in the play and my experiences as a software developer. Here are a few.

Scenes and Modularity     Each scene is a like a module that the director debugs. In some plays, the boundaries between scenes are quite clean, with a nice discrete break from one to the next. With a play on stage, the boundaries between scenes may be less clear.

In our play, scenes often blend together. Lights go down on one part of the stage and up on another, shifting the audience's attention, while the actors in the first scene remain in place. Soon, the lights shift back to the first and the action picks up where it left off. Plays work this way in part because they operate in limited real estate, and changing scenery can be time-consuming. But this also

It is easier to debug scenes that are discrete modules. Debugging scenes that run together is difficult for the same reasons that debugging code modules with leaky boundaries is. A change in one scene (say, repositioning the players) can affect the linked scene (say, by changing when and where a player enters).

Actors and Code     If the director debugs a scene, then maybe the actors, their lines, and the props are like the code. That just occurred to me while typing the last section!

Time Constraints     It is hard to get things right in a rush. Based on what he sees as the play executes, the director makes changes to the content of the show. He also refactors: rearranging the location of a prop or a player, either to "clean things up" or to facilitate some change he has in mind. It takes time to clean things up, and we only know that something needs to be changed as we watch the play run, and think about it.

Mock Objects and Stand-Ins     When rehearsing a scene, if you don't have the prop that you will use in the play itself, then use something to stand in its place. It helps you get used to the the fact that something will be there when you perform, and it helps the director remember to take into account its use and placement. You have to remember to have it at the right time in the right place, and return it to the prop table when it's not in use.

A good mock prop just needs to have some of the essential features of the actual prop. When rehearsing a scene in which I will be carrying some groceries to the car, I grabbed a box full of odds and ends out of some office. It was big enough and unwieldy enough to help me "get into the part".

Conclusion for Now     The relationship between software and plays or movies is not a new idea, of course. I seem to recall a blog entry a couple of years ago that explored the analogy of developing software as producing a film, though I can't find a link to it just now. Googling for it led me to a page on Ward's wiki and to two entries on the Confused of Calcutta blog. More reading for me... And of course there is Brenda Laurel's seminal Computers As Theatre. You really should read that!

Reading is a great way to learn, but there is nothing quite like living a metaphor to bring it home.

The value that comes from making analogies and metaphors comes in what we can we learn from them. I'm looking forward to a couple of weeks more of learning from this one -- in both directions.


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

November 27, 2007 5:45 PM

Comments on "A Program is an Idea"

Several folks have sent interesting comments on recent posts, especially A Program is an Idea. A couple of comments on that post, in particular, are worth following up on here.

Bill Tozier wrote that learning to program -- just program -- is insufficient.

I'd argue that it's not enough to "learn" how to program, until you've learned a rigorous approach like test-driven development or behavior-driven development. Many academic and scientific colleagues seem to conflate software development with "programming", and as a result they live their lives in slapdash Dilbertesque pointy-haired boss territory.

This is a good point, and goes beyond software development. Many, many folks, and especially university students, conflate programming with computer science, which disturbs academic CS folks to no end, and for good reason. Whatever we teach scientists about programming, we must teach it in a broader context, as a new way of thinking about science. This should help ameliorate some of the issues with conflating programming and computer science. The need for this perspective is also one of the reasons that the typical CS1 course isn't suitable for teaching scientists, since its goals relative to programming and computer science are so different.

I hadn't thought as much about Bill's point of conflating programming with software development. This creates yet another reason not to use CS1 as the primary vehicle for teaching scientists to ("program" | "develop software"), because even more so in this regard are the goals of CS1 for computer science majors very different from the goals of a course for scientists.

Indeed, there is already a strong tension between the goals of academic computer science and the goals of professional software development that makes the introductory CS curriculum hard to design and implement. We don't want to drag that mess into the design of a programming course for scientists, or economists, or other non-majors. We need to think about how best to help the folks who will not be computer scientists learn to use computation as a tool for thinking about, and doing work in, their own discipline.

And keep in mind that most of these folks will also not be professional software developers. I suspect that folks who are not professional software developers -- folks using programs to build models in their own discipline -- probably need to learn a different set of skills to get started using programming as a tool than professional software developers do. Should they ever want to graduate beyond a few dozen lines of code, they will need more and should then study more about developing larger and longer-lived programs.

All that said, I think that that scientists as a group might well be more amenable than many others to learning test-driven development. It is quite scientific in spirit! Like the scientific method, it creates a framework for thinking and doing that can be molded to the circumstances at hand.

The other comment that I must respond to came from Mike McMillan. He recalled having run across a video of Gerald Sussman giving a talk on the occasion of Daniel Friedman's 60th birthday, and hearing Sussman comment on expressing scientific ideas in in Scheme. This brought to his mind Minsky's classic paper "Why Programming Is a Good Medium for Expressing Poorly-Understood and Sloppily-Formulated Ideas", which is now available on-line in a slightly revised form.

This paper is the source of the oft-quoted passage that appears in the preface of Structure and Interpretation of Computer Programs:

A computer is like a violin. You can imagine a novice trying first a phonograph and then a violin. The latter, he says, sounds terrible. That is the argument we have heard from our humanists and most of our computer scientists. Computer programs are good, they say, for particular purposes, but they aren't flexible. Neither is a violin, or a typewriter, until you learn how to use it.

(Perhaps Minsky's paper is where Alan Kay picked up his violin metaphor and some of his ideas on computation-as-medium.)

Minsky's paper is a great one, worthy of its own essay sometime. I should certainly have mentioned it in my essay on scientists learning to program. Thanks to Mike for the reminder! I am glad to have had reason to track down links to the video and the PDF version of the paper, which until now I've only had in hardcopy.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

November 15, 2007 9:13 PM

Making Time to Do What You Love

Earlier this week, I read The Geomblog's A day in the life..., in which Suresh listed what he did on Monday. Research did not appear on the list.

I felt immediate and intense empathy. On Monday, I had spent all morning on our college's Preview Day, on which high school students who are considering studying CS at my university visit campus with their parents. It is a major recruiting effort in our college. I spent the early morning preparing my discussion with them and the rest of the morning visiting with them. The afternoon was full of administrative details, computer labs and registration and prospective grad students. On Tuesday, when I read the blog entry, I had taught compilers -- an oasis of CS in the midst of my weeks -- and done more administration: graduate assistantships, advising, equipment purchases, and a backlog of correspondence. Precious little CS in two days, and no research or other scholarly activity.

Alas, that is all too typical. Attending an NSF workshop this week is a wonderful chance to think about computer science, its application in the sciences, and how to teach it. Not research, but computer science. I only wish I had a week or five after it ends to carry to fruition some of the ideas swirling around my mind! I will have an opportuniy to work more on some of these ideas when I return to the office, as a part of my department's curricular efforts, but that work will be spread over many weeks and months.

That is not the sort of intense, concentrated work that I and many other academics prefer to do. Academics are bred for their ability to focus on a single problem and work intensely on it for long periods of time. Then comes academic positions that can spread us quite then. An administrative position takes that to another level.

Today at the workshop, I felt a desire to bow down before an academic who understands all this and is ready to take matters into his own hands. Some folks were discussing the shortcomings of the current Mac OS X version of VPython, the installation of which requires X11, Xcode, and Fink. Bruce Sherwood is one of the folks in charge of VPython. He apologized for the state of the Mac port and explained that the team needs a Mac guru to build a native port. They are looking for one, but such folks are scarce. Never fear, though... If they can't find someone soon, Sherwood said,

I'm retiring so that I can work on this.

Now that is commitment to a project. We should all have as much moxie! What do you say, Suresh?


Posted by Eugene Wallingford | Permalink | Categories: General, Software Development

November 10, 2007 4:21 PM

Programming Challenges

Gerald Weinberg's recent blog Setting (and Character): A Goldilocks Exercise describes a writing exercise that I've mentioned here as a programming exercise, a pedagogical pattern many call Three Bears. This is yet another occurrence of a remarkably diverse pattern.

Weinberg often describes exercises that writers can use to free their minds and words. It doesn't surprise me that "freeing" exercises are built on constraints. In one post, Weinberg describes The Missing Letter, in which the writer writes (or rewrites) a passage without using a randomly chosen letter. The most famous example of this form, known as a lipogram, is La disparition, a novel written by Georges Perec without an using the letter 'e' -- except to spell the author's name on the cover.

When I read that post months ago, I immediately thought of creating programming exercises of a similar sort. As I quoted someone in a post on a book about Open Court Publishing, "Teaching any skill requires repetition, and few great works of literature concentrate on long 'e'." We can design a set of exercises in which the programmer surrenders one of her standard tools. For instance, we could ask her to write a program to solve a given problem, but...

  • with no if statements. This is exactly the idea embodied in the Polymorphism Challenge that my friend Joe Bergin and I used to teach a workshop at SIGCSE a couple of years ago and which I often find useful in helping programmers new to OOP see what is possible.

  • with no for statements. I took a big step in understanding how objects worked when I realized how the internal iterators in Smalltalk's collection classes let me solve repetition tasks with a single message -- and a description of the action I wanted to take. It was only many years later that I learned the term "internal iterator" or even just "iterator", but by then the idea was deeply ingrained in how I programmed.

    Recursion is the usual path for students to learn how to repeat actions without a for statement, but I don't think most students get recursion the way most folks teach it. Learning it with a rich data type makes a lot more sense.

  • with no assignment statements. This exercise is a double-whammy. Without assignment statements, there is no call explicit sequences of statements, either. This is, of course, what pure functional programming asks of us. Writing a big app in Java or C using a pure functional style is wonderful practice.

  • with no base types. I nearly wrote about this sort of exercise a couple of years ago when discussing the OOP anti-pattern Primitive Obsession. If you can't use base types, all you have left are instances of classes. What objects can do the job for you? In most practical applications, this exercise ultimately bottoms out in a domain-specific class that wraps the base types required to make most programming languages run. But it is a worthwhile practice exercise to see how long one can put off referring to a base type and still make sense. The overkill can be enlightening.

    Of course, one can start with an language that provides only the most meager set of base types, thus forcing one to build up nearly all the abstractions demanded by a problem. Scheme feels like that to most students, but only a few of mine seem to grok how much they can learn about programming by working in such a language. (And it's of no comfort to them that Church built everything out of functions in his lambda calculus!)

This list operates at the level of programming construct. It is just the beginning of the possibilities. Another approach would be to forbid the use of a data structure, a particularly useful class, or an individual base type. One could even turn this idea into a naming challenge by hewing close to Weinberg's exercise and forbidding the use of a selected letter in identifiers. As an instructor, I can design an exercise targeted at the needs of a particular student or class. As a programmer, I can design an exercise targeted at my own blocks and weaknesses. Sometimes, it's worth dusting off an old challenge and doing it for it's own sake, just to stay sharp or shake off some rust.


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

November 07, 2007 8:02 PM

Magic Books and Connections to Software

Lest you all think I have strayed so far from software and computer science with my last note that I've fallen off the appropriate path for this blog, let me reassure you. I have not. But there is even a connection between my last post and the world of software, though it is sideways.

Richard Bach, the writer whom I quoted last time, is best known for his bestselling Jonathan Livingston Seagull. I read a lot of his stuff back in high school and college. It is breezy pop philosophy wrapped around thin plots, which offers some deep truths that one finds in Hinduism and other Eastern philosophies. I enjoyed his books, including his more straightforward books on flying small planes.

But one of Richard Bach's sons is James, a software tester with whose work I came into contact via Brian Marick's. James is a good writer, and I enjoy both his blog and his other writings about software, development methods, and testing. Another of Richard Bach's son, Jon, is also a software guy, though I don't know about his work. I think that James and Jon have published together.

Illusions offers a book nested inside another book -- a magic book, no less. All we see of it are the snippets that our protagonist needs to read each moment he opens it. One of the snippets from this book-within-a-book might be saying something important about an ongoing theme here:

There is no such thing as a problem without a gift for you in its hands. You seek problems because you need their gifts.

Here is the magic page that grabbed me most as I thumbed through the book again this morning:

Live never to be ashamed if anything you do or say is published around the world -- even if what is published is not true.

Now that is detachment.

How about one last connection? This one is not to software. It is an unexpected connection I discovered between Bach's work and my life after I moved to Iowa. The title character in Bach's most famous book was named for a real person, John Livingston, a world-famous pilot circa 1930. He was born in Cedar Falls, Iowa, my adopted hometown, and once even taught flying at my university, back when it was a teachers' college. The terminal of the local airport, which he once managed, is named for Livingston. I have spent many minutes waiting to catch a plane there, browsing pictures and memorabilia from his career.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

November 06, 2007 6:53 AM

Lack of Confidence and Teamwork

Over on one of the mailing lists I browse -- maverick software development -- there has been a lot of talk about how a lack of trust is one of the primary dysfunctions of teams. The discussion started as a discussion of Patrick Lencioni's The Five Dysfunctions of a Team but has taken on its own life based on the experiences of the members of the list.

One writer there made the bold claim that all team dysfunctions are rooted in a lack of trust. Others, such as fear of conflict and lack of commitment to shared goals, grow solely from a lack of trust among team members and leaders. This is, in fact, what Lencioni claims in his book, that a lack of trust creates an environment in which people fear conflict, which ensures a lack of commitment and ultimately an avoidance of accountability, ending in an inattention to the results produced by the team.

The writer who made this claim asked list members for specific counterexamples. I don't know if I can do that, but I will say that it's amazing what a lack of confidence can do to an individual's outlook and performance, and ultimately on his or her ability to contribute positively as a team member.

When a person lacks confidence in his ability, he will be inclined to interpret every contingent signal in a different way than it was intended. This interpretation is often extreme, and very often wrong. This creates an impediment to performance and to interaction.

I see it in students all the time. A lack of confidence makes it hard to learn! If I don't trust what I know or can do, then every new idea looks scary. How can I understand this if I don't understand the more fundamental material? I don't want to ask this question, because the teacher, or my classmates, will see how little I know. There's no sense in trying this; I'll just fail.

This is, I think a problem in CS classes between female and male students. Male students seem more likely than females to bluff their way through a course, pretending they understand something more deeply than they do. This gives everyone a distorted image of the overall understanding of the class, and leaves many female students thinking that they are alone in not "getting it". One of the best benefits of teaching a CS class via discussion rather than lecture is that over time the bluffers are eventually outed by the facts. I still recall one of our female students telling me in the middle of one of my courses taught in this way that she finally saw that no one else had any better grasp on the material than she did and that, all things considered, she was doing pretty well. Yes!

I see the effects of lack of confidence in my faculty colleagues, too. This usually shows up in a narrow context, where the person doesn't know a particular area of computing very well, or lacks experience in a certain forum, and as a result shies away from interacting in venues that rely on this topic. I also see this spill over into other interactions, where a lack of confidence in one area sets the tone for fear of conflict (which might expose an ignorance) and disengagement from the team.

I see it in myself, as instructor on some occasions and as a faculty member on others. Whenever possible I use a lack of confidence in my understanding of a topic as a spur to learn more and get better. But in the rush of days this ideal outlook often falls victim to rapidly receding minutes.

A personal lack of confidence has been most salient to me in my role as a department head. This was a position for which I had received no direct training, and grousing about the performance of other heads offers only the flimsiest foundation for doing a better job. I've been sensitized to nearly every interaction I have. Was that a slight, or standard operating procedure? Should I worry that my colleague is displeased with something I've done, or was that just healthy feedback? Am I doing a good enough job, or are the faculty simply tolerating me? As in so many other contexts, these thoughts snowball until they are large enough to blot everything else out of one's sight.

The claimant on the mailing list might say that trust is the real issue here. If the student trusts his teacher, or the faculty member trusts his teammates, or the department head trusts his faculty, either they would not lack confidence or would not let it affect their reactions. But that is precisely the point: they are reactions, from deep within. I think we feel our lack of confidence prior to processing the emotion and acting on trust. Lack of confidence is probably not more fundamental than lack of trust, but I think they are often orthogonal to one another.

How does one get over a lack of confidence? The simplest way is to learn what we need to know, to improve our skills. In the mean time, a positive attitude -- perhaps enabled by a sense of trust in our teammates and situation -- can do wonders. Institutionally, we can have, or work to get, support from above. A faculty member who trusts that she has room to grow in the presence of her colleagues and head, or a new department who trusts that he has room to grow in the presence of his dean, will be able to survive a lack of confidence while in the process of learning. I've seen new deans and heads cultivate that sort of trust by acting cautiously at the outset of their tenure, so as not to lose trust before the relationship is on firm ground.

In the context of software development, the set of tasks for which someone is responsible is often more crisply delineated than the set of tasks for a student or manager. In one way, that is good news. If your lack of confidence stems from not knowing how Spring or continuation passing style works, you can learn it! But it's not too simple, as there are time constraints and team relationships to navigate along the way.

Ultimately, a mindset of detachment is perhaps the best tool a person who lacks confidence can have. Unfortunately, I do not think that detachment and lack of confidence are as common a package as we might hope. Fortunately, one can cultivate a sense of detachment over time, which makes dealing with recurring doubts about one's capabilities easier to manage over time.

If only it were as easy to do these things as it is to say them!


Posted by Eugene Wallingford | Permalink | Categories: General, Managing and Leading, Software Development

November 02, 2007 1:24 PM

Refactoring, Functional Programming-Style

Back in 2002, I had a sabbatical (which are, for political reasons, called "professional development assignments" here) to document some of the patterns of programs that are written in a functional style. So much good work had been done by then on object-oriented patterns, and a few people had begun to describe OO patterns that were motivated by functional programming techniques. But few people had begun to document functional programming patterns. I had a feeling that something useful could come from moving into that space. In the end I didn't make the sort of progress I had hoped, but I did learn a lot that has continued to influence my teaching and research.

One of the areas explored as a part of that project was refactoring functional programs. I believe that refactorings are the behavioral side of patterns, and by looking at work on existing work on functional refactorings I hoped to speed my search for patterns. There hadn't been much work done on refactoring functional programs at that time, but I wasn't alone in thinking of it -- Simon Thompson and Claus Reinke were just beginning their quite productive research program on the same topic. That work, like most of the work that deals with patterns and refactoring in functional programming, focused more on the language-processing side of the topic, considering refactorings as program transformation in the vein of compiler optimizations. What seems to me still to be missing is a look at refactoring of functional programs from the software developer's perspective: I have a piece of code that I want to restructure in order to improve its design, or in order to facilitate the next addition to the program. What do I do next?

the logo of Untyped, a software firm

Noel Welsh recently wrote a blog entry called Refactoring Functional Programs that makes a very nice contribution in the space. Noel is just the sort of person who should be documenting FP patterns and refactorings, a practicing developer who works primarily in a functional or mostly functional language and who is growing a significant software system over time. His essay talks about a sequence of refactorings that he applied to his system, a web application framework, which moved one of its modules from a long-ish, overly complex, repetitive piece of code to something shorter, simpler, and well-factored. You will enjoy reading the article even if you don't program in Scheme, because Noel explains the thinking he did as he attacked this piece of code, including an alternative step that he considered but rejected due to the forces that affect his system.

For the record, his three refactorings were these. The names are part mine, part his:

  • convert mutually tail-recursive state machine to continuation-passing style
  • separate computational abstraction from control abstraction
  • convert continuation-passing style to direct style

One of the things I like about this story is how it makes a "round-trip" to CPS and back, using the trip to change the program's design in a way that might have been inaccessible otherwise. I teach my students a similar "refactoring pattern" when teaching them functional programming, make a round-trip through Mutual Recursion, by way of Program Derivation, to convert a messy one-procedure solution into a clean and one-elegant one-procedure solution.

I hope that other developers using functional programming in the trenches will follow Noel's lead and document some of the patterns and refactorings that they discover in their code and process. More than anything else, this sort of pragmatic, nuts-and-bolts writing will help to increase the accessibility of functional programming style to a wider audience of programmers.


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

October 24, 2007 4:12 PM

Missing OOPSLA

OOPSLA 2007

I am sad this week to be missing OOPSLA 2007. You might guess from my recent positive words that missing the conference would make me really sad, and you'd be right. But demands of work and family made traveling to Montreal a work infeasible. After attending eleven straight OOPSLAs, my fall schedule has a whole in it. My blog might, too; OOPSLA has been the source of many, many writing inspirations in the three years since I began blogging.

One piece of good news for me -- and for you, too -- is that we are podcasting all of OOPSLA's keynote talks this year. That would be a bonus for any conference, but with OOPSLA it is an almost sinfully delicious treat. I was reading someone else's blog recently, and the writer -- a functional programming guy, as I recall -- went down the roster of OOPSLA keynote speakers:

  • Peter Turchi
  • Kathy Sierra
  • Jim Purbrick & Mark Lentczner
  • Guy Steele & Richard Gabriel
  • Fred Brooks
  • John McCarthy
  • David Parnas
  • Gregor Kiczales
  • Pattie Maes

... and wondered if this was perhaps the strongest lineup of speakers ever assembled for a CS conference. It is an impressive list!

If you are interested in listening in on what these deep thinkers and contributors to computing are telling the OOPSLA crowd this week, checkout the conference podcast page. We have all of Tuesday's keynotes (through Steele & Gabriel in the above list) available now, and we hope to post today's and tomorrow's audio in the next day or so. Enjoy!


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

October 18, 2007 8:40 AM

Project-Based Computer Science Education

[Update: I found the link to Michael Mitzenmacher's blog post on programming in theory courses and added it below.]

A couple of days ago, a student in my compilers course was in my office discussing his team's parser project. He was clearly engaged in the challenges that they had faced, and he explained a few of the design decisions they had made, some of which he was proud of and some of which he was less thrilled with. In the course of conversation, he said that he prefers project courses because he learns best when he gets into the trenches and builds a system. He contrasted this to his algorithms course, which he enjoyed but which left him with a nagging sense of incompleteness -- because they never wrote programs.

(One can, of course, ask students to program in an algorithms course. In my undergraduate algorithms, usually half of the homework involves programming. My recent favorite has been a Bloom filters project. Michael Mitzenmacher has written about programming in algorithms courses in his blog My Biased Coin.)

I have long been a fan of "big project" courses, and have taught several different ones, among them intelligent systems, agile software development, and recently compilers. So it was with great interest I read (finally) Philip Greenspun's notes on improving undergraduate computer science education. Greenspun has always espoused a pragmatic and irreverent view of university education, and this piece is no different. With an eye to the fact that a great many (most?) of our students get jobs as professional software developers, he sums up one of traditional CS education's biggest weaknesses in a single thought: We tend to give our students

a tiny piece of a big problem, not a small problem to solve by themselves.

This is one of the things that makes most courses on compilers -- one of the classic courses in the CS curriculum -- so wonderful. We usually give students a whole problem, albeit a small problem, not part of a big one. Whatever order we present the phases of the compiler, we present them all, and students build them all. And they build them as part of a single system, capable of compiling a complete language. We simplify the problem by choosing (or designing) a smallish source language, and sometimes by selecting a smallish target machine. But if we choose the right source and target languages, students must still grapple with ambiguity in the grammar. They must still grapple with design choices for which there is no clear answer. And they have to produce a system that satisfies a need.

Greenspun makes several claims with which I largely agree. One is this:

Engineers learn by doing progressively larger projects, not by doing what they're told in one-week homework assignments or doing small pieces of a big project.

Assigning lots of well-defined homework problems is a good way to graduate students who are really good at solving well-defined homework problems. The ones who can't learn this skill change majors -- even if they would make good software developers.

Here is another Greenspun claim. I think that it is likely even more controversial among CS faculty.

Everything that is part of a bachelor's in CS can be taught as part of a project that has all phases of the engineering cycle, e.g., teach physics and calculus by assigning students to build a flight simulator.

Many will disagree. I agree with Greenspun, but to act on this idea would, as Greenspun knows, require a massive change in how most university CS departments -- and faculty -- operate.

This idea of building all courses around projects is similar to an idea I have written about many times here, the value of teaching CS in the context of problems that matter, both to students and to the world. One could teach in the context of a problem domain that requires computing without designing either the course or the entire curriculum around a sequence of increasingly larger projects. But I think the two ideas have more in common than they differ, and problem-based instruction will probably benefit from considering projects as the centerpiece of its courses. I look forward to following the progress of Owen Astrachan's Problem Based Learning in Computer Science initiative to see what role projects will play in its results. Owen is a pragmatic guy, so I expect that some valuable pragmatic ideas will come out of it.

Finally, I think students and employers alike will agree with Greenspun's final conclusion:

A student who graduates with a portfolio of 10 systems, each of which he or she understands completely and can show off the documentation as well as the function (on the Web or on the student's laptop), is a student who will get a software development job.

Again, a curriculum that requires students to build such a portfolio will look quite different from most CS curricula these days. It will also require big changes in how CS faculty teach almost every topic.

Do read Greenspun's article. He is thought-provoking, as always. And read the comments; they contain some interesting claims, too, including the suggestion that we redesign CS education as professional graduate degree program along the lines of medicine.


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

October 13, 2007 6:01 PM

More on Forth and a New Compilers Course

Remember this as a reader--whatever you are reading
is only a snapshot of an ongoing process of learning
on the part of the author.
-- Kent Beck

Sometimes, learning opportunities on a particular topic seem to come in bunches. I wrote recently about revisiting Forth and then this week ran across an article on Lambda the Ultimate called Minimal FORTH compiler and tutorial. The referenced compiler and tutorial are an unusually nice resource: a "literate code" file that teaches you as it builds. But then you also get the discussion that follows, which points out what makes Forth special, some implementation tricks, and links to several other implementations and articles that will likely keep me busy for a while.

Perhaps because I am teaching a compilers course right now, the idea that most grabbed my attention came in a discussion near the end of the thread (as of yesterday) on teaching language. Dave Herman wrote:

This also makes me think of how compilers are traditionally taught: lexing → parsing → type checking → intermediate language → register allocation → codegen. I've known some teachers to have success in going the other way around: start at the back end and move your way forward. This avoids giving the students the impression that software engineering involves building a product, waterfall-style, that you hope will actually do something at the very, *very* end -- and in my experience, most courses don't even get there by the end of the semester.

I have similar concerns. My students will be submitting their parsers on Monday, and we are just past the midpoint of our semester. Fortunately, type checking won't take long, and we'll be on to the run-time system and target code soon. I think students do feel satisfaction at having accomplished something along the way at the end of the early phases. The parser even give two points of satisfaction: when it can recognize a legal program (and reject an illegal on), and then when it produces an abstract syntax tree for a legal program. But those aren't the feeling of having compiled a program from end to end.

The last time I debriefed teaching this course, I toyed with the idea making several end-to-end passes through compilation process, inspired by a paper on 15 compilers in 15 weeks. I've been a little reluctant to mess with the traditional structure of this course, which has so much great history. While I don't want to be one of those professors who teaches a course "the way it's always been done" just for that sake, I also would like to have a strong sense that my different approach will give students a full experience. Teaching compilers only every third semester makes each course offering a scarce and thus valuable opportunity.

I suppose that there are lots of options... With a solid framework and reference implementation, we could cover the phases of the compiler in any order we like, working on each module independently and plugging them into the system as we go. But I think that there needs to be some unifying theme to the course's approach to the overall system, and I also think that students learn something valuable about the next phase in the pipeline when we build them in sequence. For instance, seeing the limitations of the scanner helps to motivate a different approach to the parser, and learning how to construct the abstract syntax tree sets students up well for type checking and conversion to an intermediate rep. I imagine that similar benefits might accrue when going backwards.

I think I'll ask Dave for some pointers and see what a backwards compiler course might look like. And I'd still like to play more with the agile idea of growing a working compiler via several short iterations. (That sounds like an excellent research project for a student.)

Oh, and the quote at the top of this entry is from Kent's addendum to his forthcoming book, Implementation Patterns. I expect that this book will be part of my ongoing process of learning, too.


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

October 10, 2007 7:10 PM

Three Lists, Three Agile Ideas

Browsing through several overflowing mailboxes from various agile software development lists -- thank the mail gods for procmail -- I ran across three messages that made save them for later reflection or use in a class.

On the extreme programming mailing list, Laurent Bossavit wrote:

> How do you deal with [a change breaks lots of tests]?

See it as an opportunity. A single change breaking a lot of tests means that your design has excessive coupling, *or* that your unit tests are written at too low a level of abstraction. This is an important and valuable thing to have learned about your code and tests.

Most of the time, we treat unexpected obstacles as problems -- either problems to solve, or problems to avoid. When we operate under time pressure, we usually try to avoid such obstacles. Students often find themselves in a bind for time and so seek to avoid problems, rather using them as an opportunity to make their programs better. This is another reason to start assignments early: to have time to be opportunistic on unexpected chances to learn!

Time pressure isn't the only reason students avoid problems. Some are driven by grades, in order to impress potential employers. (Maybe this will change in a world not driven by "getting a job".) Others are simply afraid to take the risk. Our school system does a pretty good job of beating risk-taking behavior out of students by the time they reach the university, and universities often don't do enough to undo this before they graduate into professional careers.

On the agile content of Laurent's comment, he is spot-on, of course. All those broken tests are excellent feedback on a weakness in either the system or the tests. Listen to the code.

On the Crystal Clear mailing list (dedicated to discussing "the ultralight Crystal Clear software development methodology"), methodology creator Alistair Cockburn wrote:

"Deciding what to build" is my new replacement phrase for "requirements". The word "requirements" tends to imply
  • that [someone can] correctly locate and pluck them,
  • that they are "true"

None of those are correct. They don't already pre-exist so they can't be "plucked", [no one is] in that unique position [to locate and pluck them], and they aren't "true".

which is why I nowadays prefer to talk about "deciding what to build".

I wish that more people -- software engineers, programmers, and consumers of software and software development services alike -- would think like this! "Gathering requirements" is a metaphor that goes wrong both on 'gathering' and on 'requirements'. "Deciding what to build" creates a completely different mental image and sets up a completely different set of performance expectations. As Alistair tells it, "deciding what to build" is a negotiation, not an exam question about Platonic ideals that has a correct answer. A negotiation can take into account many factors, including benefits, costs, preferences, and time.

The developer and customer can then record the results of their negotiation in a "contract" of whatever form they prefer. If they are so inclined, the contract can take the form of a set of tests that captures what the developer will deliver, say, FIT tests. When one side needs to "break the contract", the negotiation should have specified relative preferences that enable the parties to arrive at a new understanding of the system to be built. More negotiation -- not "adding a requirement" or "not delivering a requirement".

Finally, for a touch of humor, I give you this passage from a message to the refactoring mailing list from Buddha Buck:

Our team is considering implementing the refactoring "Replace C++ With Language With Good Refactoring Tool Support". It's a major refactoring, and full implementation might take months, if we decide to do it.

There have to be some pleasant steps to execute in this refactoring, and some even more pleasant milestones. That last rm *.cpp has to feel good.

More seriously, I think there is a great opportunity to write refactorings that aren't about software architecture and code. The patterns of Christopher Alexander begat the software patterns world, which caused many of us to write the patterns of other kinds of systems, including music, management, and pedagogy. In many software circles, refactorings are behavior-preserving modifications that target the patterns of the domain. If we write patterns of management or pedagogy, then why not write refactorings that help people prepare their environments for disruptive change? An interesting question comes to mind: what does it mean for a change to a management system to "preserve behavior"? This seems like a very cool avenue for some thought, even if it hits a dead end.


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

October 08, 2007 8:05 PM

Go Forth and M*

It is easy to forget how diverse the ecosphere of programming languages is. Even most of the new languages we see these days look and feel like the same old thing. But not all languages look and feel the same. If you haven't read about the Forth programming language, you should. It will remind you just how different a language can be. Forth is a stack-based language that uses postfix notation and the most unusual operator set this side of APL. I've been fond of stack-based languages since spending a few months playing with the functional language Joy and writing an interpreter for it while on sabbatical many years ago. Forth is a more of a systems language than Joy, but the programming style is the same.

I recently ran across a link to creator Chuck Moore's Forth -- The Early Years, and it offered a great opportunity to reacquaint myself with the language. This paper is an early version of the paper that became the HOPL-2 paper on Forth, but it reads more like the notes of a talk -- an informal voice, plenty of sentence fragments, and short paragraphs that give the impression of stream of consciousness.

This "autobiography of Forth" is a great example of how a program evolves into a language. Forth started as a program to compute a least-squares fitting of satellite tracking data to determine orbits, and it grew into an interpreter as Moore bumped up against the limitations of the programming environment on the IBM mainframes of the day. Over time, it grew into a full-fledged language as Moore took it with him from job to job, porting it to new environments and extending it to meet the demands of new projects. He did not settle for the limitations of the tools available to him; instead, he thought "There must be a better way" -- and made it so.

As someone teaching a compilers course right now, I smiled at the many ways that Forth exemplified the kind of thinking we try to encourage in students learning to write a compiler. Moore ported Forth to Fortran and back. He implemented cross-assemblers and code generators. When speed mattered, he wrote native implementations. All the while, he kept the core of the language small, adding new features primarily as definitions of new "words" to be processed within the core language architecture.

My favorite quotes from the paper appear at the beginning and the end. To open, Moore reports that he experienced what is in many ways the Holy Grail for a programmer. As an undergraduate, he took a part-time job with the Smithsonian Astrophysical Observatory at MIT, and...

My first program, Ephemeris 4, eliminated my job.

To close, Moore summarizes the birth and growth of Forth as having "the making of a morality play":

Persistent young programmer struggles against indifference to discover Truth and save his suffering comrades.

This is a fine goal for any computer programmer, who should be open to the opportunity to become a language designer when the moment comes. Not everyone will create a language that lasts for 50 years, like Forth, but that's not the point.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

October 06, 2007 8:16 PM

Today I Wrote a Program

Today I wrote a program, just for fun. I wrote a solution to the classic WordLadder game, which is a common nifty assignment used in the introductory Data Structures course. I had never assigned it in one of my courses and had never had any other reason to solve it. But my daughter came home yesterday with a math assignment that included a few of these problems, such as converting "heart" to "spade", and in the course of talking with her I ended up doing a few of the WordLadder problems on my own. I'm a hopeless puzzle junkie.

Some days, an almost irrational desire to write a program comes over me, and last night's fun made me think, "I wonder how I might do this in code?" So I used a few spare minutes throughout today to implement one of my ideas from last night -- a simple breadth-first search that finds all of the shortest solutions in a particular dictionary.

A few of those spare minutes came at the public library, while the same daughter was participating in a writers' workshop for youth. As I listened to their discussion of a couple of poems written by kids in the workshop in the background, I thought to myself, "I'm writing here, too." But then it occurred to me that the kids in the workshop wouldn't call what I was doing "writing". Nor would their workshop leader or most people that we call "writers". Nor would most computer scientists, not without the rest of the phrase: "writing a program".

Granted, I wasn't writing a poem. But I was exploring an idea that had come into my mind, one that drove forward. I wasn't sure what sort of program I would end up, and arrived at the answer only after having gone down a couple of expected paths and found them wanting. My stanzas, er, subprocedures, developed over time. One grew and shrank, changed name, and ultimately became much simpler and clearer than what I had in mind when I started.

I was telling a story as much as I was solving a problem. When I finished, I had a program that communicates to my daughter an idea I described only sketchily last night. The names of my variables and procedures tell the story, even without looking at too much of their detail. I was writing as a way to think, to find out what I really thought last night.

Today I wrote a program, and it was fun.


Posted by Eugene Wallingford | Permalink | Categories: General, Software Development

October 05, 2007 4:45 PM

Fear and Loathing in the Computer Lab

I occasionally write about how students these days don't want to program. Not only don't they want to do it for a living, they don't even want to learn how. I have seen this manifested in a virtual disappearance of non-majors from our intro courses, and I have heard it expressed by many prospective CS majors, especially students interested in our networking and system administration majors.

First of all, let me clarify something. When I say talk about students not wanting to program, one of my colleagues chafes, because he thinks I mean that this is an unchangeable condition of the universe. I don't. I think that the world could change in a way that kids grow up wanting to program again, the way some kids in my generation did. Furthermore, I think that we in computer science can and should help try to create this change. But the simple fact is that nearly all the students who come to the university these days do not want to write programs, or learn how to do so.

If you are interested in this issue, you should definitely read Mark Guzdial's blog. Actually, you should read it in any case -- it's quite good. But he has written passionately about this particular phenomenon on several occasions. I first read his ideas on this topic in last year's entry Students find programming distasteful, which described experiences with non-majors working in disciplines where computational modeling are essential to future advances.

This isn't about not liking programming as a job choice -- this isn't about avoiding facing a cubicle engaged in long, asocial hours hacking. This is about using programming as a useful tool in a non-CS course. It's unlikely that most of the students in the Physics class have even had any programming, and yet they're willing to drop a required course to avoid it.

In two recent posts [ 1 | 2 ], Mark speculates that the part of the problem involving CS majors may derive from our emphasis on software engineering principles, even early in the curriculum. One result is an impression that computer science is "serious":

We lead students to being able to create well-engineered code, not necessarily particularly interesting code.

One result of that result is that students speak of becoming a programmer as if this noble profession has its own chamber in one of the middle circles in Dante's hell.

I understand the need for treating software development seriously. We want the people who write the software we use and depend upon every day to work. We want much of it to work all the time. That sounds serious. Companies will hire our graduates, and they want the software that our graduates write to work -- all the time, or at least better than the software of their competitors. That sounds serious, too.

Mark points out that, while this requirement on our majors calls for students to master engineering practice, it does "not necessarily mesh with good science practice".

In general, code that is about great ideas is not typically neat and clean. Instead, the code for the great programs and for solving scientific problems is brilliant.

And -- here is the key -- our students want to be creative, not mundane.

Don't get me wrong here. I recently wrote on the software engineering metaphor as mythology, and now I am taking a position that could be viewed as blaming software engineering for the decline of computer science. I'm not. I do understand the realities of the world our grads will live in, and I do understand the need for serious software developers. I have supported our software engineering faculty and their curriculum proposals, including a new program in software testing. I even went to the wall for an unsuccessful curriculum proposal that created some bad political feelings with a sister institution.

I just don't want us to close the door to our students' desire to be brilliant. I don't want to close the door on what excites me about programming. And I don't want to present a face of computing that turns off students -- whether they might want to be computer scientists, or whether they will be the future scientists, economists, and humanists who use our medium to change the world in the ways of those disciplines.

Thinking cool ideas -- ideas that are cool to the thinker -- and making them happen is intellectually rewarding. Computer programming is a new medium that empowers people to realize their ideas in a way that has never been available to humankind before.

As Mark notes in his most recent article on this topic, realizing one's own designs also motivates students to want to learn, and to work to do it. We can use the power of our own discipline to motivate people to sample it, either taking what they need with them to other pastures or staying and helping us advance the discipline. But in so many ways we shoot ourselves in the foot:

Spending more time on comments, assertions, preconditions, and postconditions than on the code itself is an embarrassment to our field.

Amen, Brother Mark.

I need to do more to advance this vision. I'm moving slowly, but I'm on the track. And I'm following good leaders.


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

October 04, 2007 6:40 PM

OOPSLA Evolving

I have like to write programs since I first learned Basic in high school. When I discovered OOPSLA back in 1996, I felt as if I had found a home. I had been programming in Smalltalk for nearly a decade. At the time, OOP was just reaching down into the university curriculum, and the OOPSLA Educators' Symposium introduced me to a lot of smart, interesting people who were wrestling with some of the questions we were wrestling with her.

But the conference was about more than objects. It had patterns, and agile software development, and aspect-oriented programming, and language processing, and software design more generally. It was about programs. The people at OOPSLA liked to write programs. They liked to look at programs, discuss, and explore new ways of writing them. I was hooked.

When objects were in ascendancy in industry, OOPSLA had the perfect connection to academia and industry. That was useful. But now that OOP has become so mainstream as to lose its sense of urgency, the value of having "OO" in the conference name has declined. Now, the "OO" part of the name is more misleading than helpful. In some ways, it was an accident of history that this community grew up around object-oriented programming. Its real raison d'etre is programming.

The conference cognoscenti have been bandying about the idea of changing the name of the conference for a few years now, to communicate better why someone should come to the conference. This is a risky proposition, as the OOPSLA name is a brand that has value in its own right.

You can see one small step toward the possibility of a new name in how we have been "branding" the conference this year. On the 2007 web site, instead of saying "OOPSLA" we have been saying ooPSLA. There are a couple of graphical meanings one can impose on this spelling, but it is a change that signals the possibility of more.

It has been fun hearing the discussions of a possible name change. You can see glimpses of the "OOPSLA as programming" theme, and some of the interesting ideas driving thoughts of change, in this year's conference program. General chair Richard Gabriel writes:

I used to go to OOPSLA for the objects -- back in the 1980s when there was lots to find/figure out about objects and how that approach -- oop -- related to programming in general. Nowadays objects are mainstream and I go for the programming. I love programs and programming. I laugh when people try to compare programming to something else, such as: "programming is like building a bridge" or "programming is like following a recipe to bake a soufflé." I laugh because programming is the more fundamental activity -- people should be comparing other things to it: "writing a poem is like programming an algorithm" or "painting a mural is like patching an OS while it's running." I write programs for fun the way some people play sudoku or masyu, and so I love to hear and learn about programs and programming.

Programming is the more fundamental activity... Very few people in the world realize this -- including a great many computer scientists. We need to communicate this better to everyone, lest we fail to excite the great minds of the future to help us build this body of knowledge.

OOPSLA has an Essays track that distinguishes it from other academic conferences. An OOPSLA essay enables an author to reflect ...

... upon technology, its relation to human endeavors, or its philosophical, sociological, psychological, historical, or anthropological underpinnings. An essay can be an exploration of technology, its impacts, or the circumstances of its creation; it can present a personal view of what is, explore a terrain, or lead the reader in an act of discovery; it can be a philosophical digression or a deep analysis. At its best, an essay is a clear and compelling piece of writing that enacts or reveals the process of understanding or exploring a topic important to the OOPSLA community. It shows a keen mind coming to grips with a tough or intriguing problem and leaves the reader with a feeling that the journey was worthwhile.

As 2007 Essays chair Guy Steele writes in his welcome,

Perhaps we may fairly say that while Research Papers focus on 'what' and 'how' (aided and abetted by 'who' and 'when' and 'where'), Essays take the time to contemplate 'why' (and Onward! papers perhaps brashly cry 'why not?').

This ain't your typical research paper, folks. Writers are encouraged to think big thoughts about programs and programming, and then share those thoughts with an audience that cares.

Steele refers to Onward!, and if you've never been to OOPSLA you may not be able to what he means. In many ways, Onward! is the archetypal example of how OOPSLA is about programs and all the issues related to them. A few years ago, many conference folks were frustrated that the technical track at OOPSLA made no allowance for papers that really push the bounds of our understanding, because they didn't fit neatly into the mold of conventional programming languages research. Rather than just bemoan the fact, these folks -- led by Gabriel -- created the conference-within-a-conference that is Onward!. Crista Lopes's Onward! welcome leaves no doubt that the program is the primary focus of the Onward! and, more generally, the conference:

Objects have grown up, software is everywhere, and we are now facing a consequence of this success: the perception that we know what programming is all about and that building software systems is, therefore, just a simple matter of programming ... with better or worse languages, tools, and processes. But we know better. Programming technology may have matured, programming languages, tools, and processes may have proliferated, but fundamental issues pertaining to computer Programming, Systems, Languages, and Applications are still as untamed, as new, and as exciting as they ever were.

Lopes also wrote a marvelous message on the conference mailing list last October that elaborates on these ideas. She argued that we should rename OOPSLA simply the ACM Conference on Programming. I'll quote only this portion:

Over the past couple of decades, the words "programming" and "programmer" fell out of favor, and were replaced by several other expressions such as "software engineer(ing)", "software design(er)", "software architect(ure)", "software practice", etc. A "programmer" is seen in some circles as an inferior worker to a "software engineer" or, pardon the comparison!, a "software architect". There are now endless, more fashionable terms that try to hide, or subsume, the fact that, when the rubber hits the road, this is all about developing systems whose basic elements are computer programs, and the processes and tools that surround their creation and composition.

...

While I have nothing against the new, more fashionable terms, and even understand their need and specificity, I think it's a big mistake that the CS research community follows the trend of forgetting what this is all about. The word "programming" is absolutely right on the mark!, and CS needs a research community focusing on it.

On this view, we need to rename OOPSLA not for OOPSLA's sake, but for the discipline's. Lopes's "Conference on Programming" sounds to bland to those with a marketing bent and too pedestrian for those who with academic pretension. But I'm not sure that it isn't the most accurate name.

What are the options? For many, then default is to drop the "oo" altogether, but that leaves PSLA -- which breaks whatever rule there is against creating acronyms that sound unappealing when said out loud. So I guess the ooPSLA crowd should just keep looking.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

October 03, 2007 5:24 PM

Walk the Wall, Seeger

Foley break Mayo

There is a great scene toward the end of one of my favorite movies, An Officer and a Gentleman. The self-centered and childlike protagonist, Zach Mayo, has been broken down by Drill Instructor Foley. He is now maturing under the Foley's tough hand. The basic training cohort is running the obstacle course for its last time. Mayo is en route to a course record, and his classmates are urging him on. But as his passes one of his classmates on the course, he suddenly stops. Casey Seeger has been struggling with wall for the movie, and it looks like she still isn't going to make it. But if she doesn't, she won't graduate. Mayo sets aside his record and stands with Seeger, cheering her and coaching her over the wall. Ultimately, she makes it over -- barely -- and the whole class gathers to cheer as Mayo and Seeger finish the run together. This is one of the triumphant scenes of the film.

I thought of this scene while running mile repeats on the track this morning. Three young women in the ROTC program were on the track, with two helping the third run sprints. The two ran alongside their friend, coaxing her and helping her continue when she clearly wanted to stop. If I recall correctly from my sister's time in ROTC, morning PT (physical training) is a big challenge for many student candidates and, as in An Officer and a Gentleman, they must meet certain fitness thresholds in order to proceed with the program -- even if they are in non-combat roles, such as nurses.

It was refreshing to see that sort of teamwork, and friendship, among students on the track.

It is great when this happens in one our classes. But when it does, it is generally an informal process that grows among students who were already friends when they came to class. It is not a part of our school culture, especially in computer science.

Some places, it is part of the culture. A professor here recently related a story from his time teaching in Taiwan. In his courses there, the students in the class identified a leader, and then they worked together to make sure that everyone in the class succeeded. This was something that students expected of themselves, not something the faculty required.

I have seen this sort of collectivism imposed from above by CS professors, particularly in project courses that require teamwork. In my experience, it rarely works well when foisted on students. The better students resent having their grade tied to a weaker student's, or a lazier one's. (Hey, it's all about the grade, right?) The weaker students resent being made someone else's burden. Maybe this is a symptom of the Rugged Individualism that defines the West, but working collectively is generally just not part of our culture.

And I understand how the students feel. When I found myself in situations like this as a student, I played along, because I did what my instructors asked me to do. And I could be helpful. But I don't think it ever felt natural to me; it was an external requirement.

Recently I found myself discussing pair programming in CS1 with a former student who now teaches for us. He is considering pairing students in the lab portion of his non-majors course. Even after a decade, he remembers (fondly, I think) working with a different student each week in my CS1 lab. But the lab constituted only a quarter of the course grade, and the lab exercises did not require long-term commitment to helping the weakest members of the class succeed. Even still, I had students express dissatisfaction at "wasting their time".

This is one of the things that I like about the agile software methods: it promotes a culture of unity and of teamwork. Pair programming is one practice that supports this culture, but so are collective ownership, continuous integration, and coding standard. Some students and programmers, including some of the best, balk at being forced into "team". Whatever the psychological, social, and political issues, and whatever my personal preferences as a programmer, there seems something attractive about a team working together to get better, both as a team and as individuals.

I wish the young women I saw this morning well. I hope they succeed, as a team and as individuals. They can make it over the wall.


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

October 02, 2007 6:58 AM

The Right (Kind of) Stuff

As you seek the three great virtues of a programmer, you seek to cultivate...

... the kind of laziness that makes you want to minimize future effort but investing effort today, to maximize your productivity and performance over the long haul, not the kind that leads you to avoid essential work or makes you want to cut corners.

... the kind of impatience that encourages you to work harder, not the kind of impatience that steals your spirit when you hit a wall or makes you want to cut corners.

... the kind of hubris that makes you think that you can do it, to trust yourself, not the kind of hubris that makes you think you don't have to listen to the problem, your code, or other people -- or the kind that makes you want to cut corners.


Posted by Eugene Wallingford | Permalink | Categories: General, Software Development

September 26, 2007 6:42 PM

Updates, Courtesy of My Readers

I love to hear from readers who have enjoyed an article. Often, folks have links or passages to share from their own study of the same issue. Sometimes, I feel a need to share those links with everyone. Here are three, in blog-like reverse chronological order:

On Devil's Advocate for Types

Geoff Wozniak pointed me in the direction of Gilad Bracha's work on pluggable type systems. I had heard of this idea but not read much about it. Bracha argues that a type system should be a wrapper around the dynamically typed core of a program. This makes it possible to expose different views of a program to different readers, based on their needs and preferences. More thinking to do...

On Robert Lucky and Math Blues

Chris Johnson, a former student of mine, is also a fan of Bob Lucky's. As a graduate student in CS at Tennessee, though, he qualifies for a relatively inexpensive IEEE student membership and so can get his fix of Lucky each month in Spectrum. Chris took pity on his old prof and sent me a link to Lucky's Reflections on-line. Thank you, thank you! More reading to do...

On Would I Lie to You?

Seth Godin's thesis is that all good marketers "lie" because they tell a story tailored to their audience -- not "the truth, the whole truth, and "nothing but the truth". I applied his thesis to CS professors and found it fitting.

As old OOSPLA friend and colleague Michael Berman reminds us, this is not a new idea:

Another noteworthy characteristic of this manual is that it doesn't always tell the truth.... The author feels that this technique of deliberate lying will actually make it easier for you to learn the ideas.

That passage was written by Donald Knuth in the preface to The TEXbook, pages vi-vii. Pretty good company to be in, I'd say, even if he is an admitted liar.

Keep those suggestions coming, folks!


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

September 26, 2007 9:00 AM

Program, Teach, Sleep...

... choose any two.

In a recent blog entry, JRuby developer Charles Nutter claimed that, in general, "[g]ood authors do not have time to be good developers". This post has engendered a fair amount of discussion, but I'm not sure why. It shouldn't surprise anyone that staying on top of your game in one time-consuming discipline makes it hard, if not impossible to stay on top of your game in a second time-consuming discipline. There are so many hours in a day, and only so many brain cycles to spend learning and doing.

I face this trade-off, but between trying to be a good teacher and trying to be a good developer. Like authors, teachers are in a bind: To teach a topic well, we should do it well. To do it well takes time. But the time we spend learning and doing it well is time that we can't spend teaching well. The only chance we have to do both well is to spend most of our time doing only these two activities, but that can mean living a life out of balance.

If I had not run for 3-1/2 hours last Sunday, I suppose that I could have developed another example for my class or written some Ruby. But would I have been better off? Would my students? I don't know.

While I have considered the prospect of writing a textbook, I've not yet found a project that made me want to give up time from my teaching, my programming, my running, and my family. Like Nutter, I like to write code. This blog gives me an opportunity to write prose and to reach readers with my ideas, while leaving me the rest of the day to teach, to perhaps to help others learn to like to write code by my example.


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

September 24, 2007 4:47 PM

Devil's Advocate for Types

A couple of my recent entries (here and here) have questioned the value of data types, at least in relation to a corresponding set of unit tests. While running this weekend, I played devil's advocate with myself a bit, thinking, "But what would a person who prefers programming with manifest types say?"

One thing that types provide that tests do not is a sense of universality. I can write a test for one case, or two, or ten, but at the end of the day I will have only a finite number of test cases. A type checker can make a more general statement, of a more limited scope. The type checker can say, "I don't know the values of all possible inputs, but I do know that all of the values are integers." That information can be quite useful. A compiler can use it to generate more efficient target code. A programmer can use it to generalize more confidently from a small set of tests to the much larger set of all possible tests.

In the terms of unit testing, types give us a remarkable level of test coverage for a particular kind of test case.

This is a really useful feature of types. I'd like to take advantage of it, even if I don't want my language to get in my way very much while I'm writing code. One way I can have both is to use type inference -- to let my compiler, or more generally my development environment, glean type information from my code and use that in ways that help me.

There is another sense in which we object-oriented programmers use types without thinking about them: we create objects! When I write a class, I define a set of objects as an abstraction. Such an object is specified in terms of its behavioral interface, which is public, and its internal state, which is private. This creates a kind of encapsulation that is just like what a data type provides. In fact, we often do think of classes as abstract data types, but with the twist that we focus on an object's behavioral responsibility, rather than manipulating its state.

That said, newcomers to my code benefit from manifest types because the types point them to the public interface expected of the objects that appear in the various contexts of my program.

I think this gets to the heart of the issue. Type information is incredibly useful, and helps the reader of a program in ways that a set of tests does not. When I write a programs with a data-centric view of my abstractions, specifying types up front seems not only reasonable but almost a no-brainer. But when I move away from a data-centric view to a behavioral perspective, tests seem to offer a more flexible, comfortable way to indicate the requirements I place on my objects.

This is largely perception, of course, as a Java-style interface allows me to walk a middle road. Why not just define an interface for everything and have the benefits of both worlds? When I am programming bottom-up, as I often do, I think the answer comes down to the fact that I don't know what the interfaces should look like until I am done, and fiddling with manifest types along the way slows me down at best and distracts me from what is important at worst. By the time I know what my types should look like, they are are of little use to me as a programmer; I'm on to the next discovery task.

I didn't realize that my mind would turn to type inference when I started this line of questioning. (Thinking and writing can be like that!) But now I am wondering how we can use type inference to figure out and display type information for readers of code when it will be useful to them.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

September 20, 2007 6:55 AM

Hype, or Disseminating Results?

The software world always seems to have a bandwagon du jour, which people are either riding or rebelling against. When extreme programming became the rage a while back, all I seemed to hear from some folks was that "agile" was a buzzword, a fad, all hype and no horse. Object-oriented programming went through its bandwagon phase, and Java had its turn. Lately it seems Ruby is the target of knowing whispers, that its popularity is only the result of good marketing, and it's not really all that different.

But what's the alternative? Let's see what Turing Award winner Niklaus Wirth has to say:

Why, then, did Pascal capture all the attention, and Modula and Oberon got so little? Again I quote Franz: "This was, of course, partially of Wirth's own making". He continues: "He refrained from ... names such as Pascal-2, Pascal+, Pascal 2000, but instead opted for Modula and Oberon". Again Franz is right. To my defense I can plead that Pascal-2 and Pascal+ had already been taken by others for their own extensions of Pascal, and that I felt that these names would have been misleading for languages that were, although similar, syntactically distinct from Pascal. I emphasized progress rather than continuity, evidently a poor marketing strategy.

But of course the naming is by far not the whole story. For one thing, we were not sufficiently active -- today we would say aggressive -- in making our developments widely known.

Good names and aggressive dissemination of ideas. (Today, many would call that "marketing".)

Wirth views Pascal, Modula, and Oberon as an ongoing development of 25 years that resulted in a mature, elegant, and powerful language, a language who couldn't even imagine back in 1969. Yet for many software folks, Modula was a blip on the scene, or maybe just a footnote, and Oberon was, well, most people just say "Huh?" And that's a shame, because even if we choose not to program in Oberon, we lose something by not understanding what it accomplished as a language capable of supporting teams and structured design across the full array of system programming.

I never faulted Kent Beck for aggressively spreading XP and the ideas it embodied. Whatever hype machine grew up around XP was mostly a natural result of people becoming excited by something that could so improve their professional practice. Yes, I know that some people unscrupulously played off the hype, but the alternative to risking hype is anonymity. That's no way to change the world.

I also applaud Kent for growing as he watched the results of XP out in the wild and for folding that growth back into his vision of XP. I wonder, though, if the original version of XP will be Pascal to XP2e's Modula.

By the way, the Wirth quote above comes from his 2002 paper Pascal and Its Successors. I enjoy hearing scientists and engineers tell the stories of their developments, and Wirth does a nice job conveying the context in which he developed Pascal, which had a great many effects in industry but more so in the academic world, and its progeny. As I read, I reacted to several of his remarks:

  • On Structured Programming:

    Its foundations reached far deeper than simply "programming without go to statements" as some people believed. It is more closely related to the top-down approach to problem solving.

    Yes, and in this sense we can more clearly see the different mindset between the Structured Programming crowd and the bottom-up Lisp and Smalltalk crowd.

  • On static type checking:

    Data typing introduces redundancy, and this redundancy can be used to detect inconsistencies, that is, errors. If the type of all objects can be determined by merely reading the program text, that is, without executing the program, then the type is called static, and checking can be performed by the compiler. Surely errors detected by the compiler are harmless and cheap compared to those detected during program execution in the field, by the customer.

    Well, yeah, but what if I write tests that let me detect the errors in house -- and tell more about my program and intentions than manifest types can?

  • On loopholes in a language:

    The goal of making the language powerful enough to describe entire systems was achieved by introducing certain low-level features.... Such facilities ... are inherently contrary to the notion of abstraction by high-level language, and should be avoided. They were called loopholes, because they allow to break the rules imposed by the abstraction. But sometimes these rules appear as too rigid, and use of a loophole becomes unavoidable. The dilemma was resolved through the module facility which would allow to confine the use of such "naughty" tricks to specific, low-level server modules. It turned out that this was a naive view of the nature of programmers. The lesson: If you introduce a feature that can be abused, then it will be abused, and frequently so!

    This is, I think, a fundamental paradox. Some rules, especially in small, elegant languages, don't just appear too rigid; they are. So we add accommodations to give the programmer a way to breach the limitation. But then programmers use these features in ways that circumvent the elegant theory. So we take them out. But then...

    The absence of loopholes is the acid test for the quality of a language. After all, a language constitutes an abstraction, a formal system, determined by a set of consistent rules and axioms. Loopholes serve to break these rules and can be understood only in terms of another, underlying system, an implementation.

    Programming languages are not (just) formal systems. They are tools used by people. An occasional leak in the abstraction is a small price to pay for making programmers' lives better. As Spolsky says, "So the abstractions save us time working, but they don't save us time learning."

    A strong culture is a better way to ensure that programmers don't abuse a feature to their detriment than a crippled language.

All that said, we owe a lot to Wirth's work on Pascal, Modula, and Oberon. It's worth learning.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

September 18, 2007 6:06 PM

A Great Feeling

A good friend sent me a note today that ended like this:

I feel like this has opened up a whole new world, a whole new way of thinking about programming. In fact, I haven't had such a feeling ... since my early days of first learning Pascal and the days of discovering data structures, for loops, recursion, etc...

I know this sensation and hope every person -- student and professional -- gets to feel it every so often. Students, seek it out by taking courses that promise more than just more of the same. Professionals, seek it out by learning a new kind of language, a new kind of web framework, a new kind of programming. This feeling is worth the effort, and makes your life better as a result.


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

September 17, 2007 6:40 PM

Language Choice and Inheriting a Codebase

In an XP mailing list thread "Are current "popular" programming languages enterprise grade?", someone raised a concern that some languages result in "buggier" code. William Pietri responded to a more general concern:

From the "enterprise" perspective, I think there's some legitimate worry about more flexible languages.

If I have to inherit a great code base, I'm sure I'd be happy if it were in Ruby. But if I have to inherit a bad one, I'd rather it be in Java. Its surly and restrictive nature makes some sorts of archeology easier, partly because it prevents some of Ruby's beautiful magic.

Now personally, I'd solve this problem by making sure all code bases are great ones. But if one already has a culture of tolerance for mediocrity and/or building one's house on sand, then restricting people to "safe" tool choices isn't crazed.

Maybe I haven't been paying attention, but this is the first time I recall seeing someone say in quite this way why "better" languages are risky for general use. A more powerful language enables beautiful magic that makes digging into a new codebase more difficult. The claim seems to be that it is easier to understand bad code written in a less powerful language.

I'm not sure how I feel about this claim just yet. Is it really easier for a Scheme programming expert to understand bad Scheme code than bad Java code? Is difficulty more a function of the beautiful magic a language allows, or more a function of the programmer's skill. William speaks of his inheriting someone else's bad code, but maybe our concern should be a weak programmer inheriting someone else's bad code? This is the heart of many people's concerns with using powerful but non-mainstream languages in production systems, that there just aren't enough good programmers prepared to work in those languages.

But William's answer has me thinking. It provoked another interesting message, Phlip's response that took the claim in a different direction:

That's just a way to say this

...static typing is a form of unit tests
...Java enforces static typing viciously
...I'd rather inherit a project with any unit tests.

This is a great way to think about manifest typing: Types are a degenerate form of unit test, and languages that enforce manifest types require programmers to write degenerate tests. In Phlip's idea, William is happy to receive a bad Java codebase because at least it has types as tests. But if the Ruby codebase you inherit comes with unit tests...

Many agile developers extol the virtue of programming in more flexible -- and powerful -- languages, and most know that by writing tests they mitigate the loss of manifest typing and end up with a net win: code whose tests tell us much more than the manifest types would have anyway, and they benefited from using a more powerful language. I'd argue that for a large many programmers, using a more powerful language can be a lot more fun, too.

Ultimately, the issue comes back to an old question: Can we prepare the majority of programmers to use Scheme, Ruby, Smalltalk, or Haskell effectively enough to make them suitable for the mainstream. I still think yes, and believe that the drifting of powerful concepts into popular languages such as Ruby is a sign of gradual gains. Whether this pans out in the long run, we'll have to see.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

September 15, 2007 11:05 AM

Software Engineering Metaphor, Mythology, and Truth

We often speak of metaphors for software development, but what we are really talking about is a mythology. Until this morning, I forgot that I had already written about this topic back in September 2004, when I wrote Myth and Patterns about a session led by Norm Kerth at PLoP that year. I just re-read that piece and had two thoughts. One, what a great day that was! And two, I don't have much new to say on this topic after all. I was jazzed this morning to talk about the fact that software engineering is more a mythology of software development than a meaningful metaphor for doing it.

Why jazzed? Recently I ran across a satirical fable entitled Masterpiece Engineering by Thomas Simpson, which appears as an appendix in Brian Randell's reminiscence of having edited the reports of the 1968-196969 NATO Software Engineering conferences. Simpson's satire made light of the software engineering metaphor by comparing it the engineering of artistic masterpieces. He wrote it in response to the unexpected tone of the second NATO conference, held in 1969. The first conference is famous for being where the term "software engineering" was coined, more as a thought experiment about software developers might strive for than anything else. But, as Randell writes, the second conference took some participants by surprise:

Unlike the first conference, at which it was fully accepted that the term software engineering expressed a need rather than a reality, in Rome there was already a slight tendency to talk as if the subject already existed. And it became clear during the conference that the organizers had a hidden agenda, namely that of persuading NATO to fund the setting up of an International Software Engineering Institute.

Show me the money. Some things never change.

However things did not go according to their plan. The discussion sessions which were meant to provide evidence of strong and extensive support for this proposal were instead marked by considerable scepticism...

I'm glad that I found Simpson's satire and Randell's report. I enjoyed both, and they caused me to look back to my blog on Kerth's PLoP session. Reading it again caused me to think again about what I had planned to write this morning. That old piece reminded me of something I've forgotten: myths embody truth. I was set to diss the engineering metaphor as "nothing but a story", but I had forgotten that we create myths to help us explain the ways of the universe. They contain some truths, sometimes filled out with fanciful details whose primary purpose are to make us want to hear the story -- and tell it to others. "Deep truths often lie inside stories that are themselves not strictly factual."

So rather than to speak ill of software engineering, the worst I can say this morning that we became too self-important in the software engineering myth too soon. We came to believe that all the filler -- all of the details we borrowed from engineering to make the story more complete -- were true, too. We created an orthodoxy out of what was really just a great source of inspiration to find our own way in the challenging world of creating software.

Maybe we have learned enough in the last forty years to know that much of the software engineering myth no longer matches our understanding of the world, but we aren't willing to give up the comfort of the story.

What we need to do is to identify the deep truths that lie at the heart of our myth, and use them to help us move on to something better. I think Ward and Kent did that when they created XP. But it, too, has now reached an age at which we should deconstruct it, identify its essential truths, and create something better. Fortunately, the culture of XP and other agile approaches not only allows this growth; it encourages it. The agile myth is meant "to be shaped to its environment, retold in as many different forms as there are tellers, as we all work together to find deeper truths about how to build better software better."

I'm still learning from a conference I attended three years ago this weekend.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

August 31, 2007 5:39 PM

Good Writing, Good Programming

This week I ran across a link to an old essay called Good Writing, by Marc Raibert. By now I shouldn't be so happy to be reminded how much good programming practice is similar to good writing in general. But I usually am. The details of Raibert's essay are less important to me than some of his big themes.

Raibert starts with something that people often forget. To write well, one must ordinarily want to write well and believe that one can. Anyone who teaches introductory computer science knows how critical motivation and confidence are. Many innovations in CS1 instruction over the years have been aimed at helping students to develop confidence in the face of what appear to be daunting obstacles, such as syntax, rigor, and formalism. Much wailing and gnashing of teeth has followed the slowly dawning realization that students these days are much less motivated to write computer programs than they have been over most of the last thirty years. Again, many innovations and proposals in recent years have aimed at motivating students -- more engaging problems, media computation, context in the sciences and social sciences, and so on. These efforts to increase motivation and confidence are corporate efforts, but Raibert reminds us that, ultimately, the individual who would be a writer must hold these beliefs.

After stating these preconditions, Raibert offers several pieces of advice that apply directly to computing. Not surprisingly, my favorite was his first: Good writing is bad writing that was rewritten. This fits nicely in the agile developer's playbook. I think that few developers or CS teachers are willing to say that it's okay to write bad code and then rewrite. Usually, when folks speak in terms of do the simplest thing that will work and refactor mercilessly, they do not usually mean to imply that the initial code was bad, only that it doesn't worry inordinately about the future. But one of the primary triggers for refactoring is the sort of duplication that occurs when we do the simplest thing that will work without regard for the big picture of the program. Most will agree that most such duplication is a bad thing. In these cases, refactoring takes a worse program and creates a better one.

Allowing ourselves to write bad code empowers us, just as it empowers writers of text. We need not worry about writing the perfect program, which frees us to write code that just works. Then, after it does, we can worry about making the program better, both structurally and stylistically. But we can do so with the confidence that comes from knowing that the substance of our program is on track.

Of course, starting out with the freedom to write bad code obligates us to re-write, to refactor, just as it obligates writers of text to re-write. Take the time! That's how we produce good code reliably: write and re-write.

I wish more of my freshmen would heed this advice:

The first implication is that when you start a new [program], there is nothing wrong with using bad writing. Your goal when you start is to get your ideas down on paper in any form you can.

For the novice programmer, I do not recommend writing ungrammatical or "stream of consciousness" code, but I do encourage them to take the ideas they have after having thought about the problem and expressing them in code. The best way to find out if an idea is a good one is to see it run in code.

Raibert's other advice also applies. When I read Spill the beans fast, I think of making my code transparent. Don't hide its essence in subterfuge that makes me seem clever; push its essence out where all can see it and understand the code. Many of the programmers whose code I respect most, such as Ward Cunningham, write code that is clear, concise, and not at all clever. That's part of what makes it beautiful.

Don't get attached to your prose is essential when writing prose, and I think it applies to code as well. Just because you wrote a great little method or class yesterday doesn't mean that it should survive in your program of tomorrow. While programming, you discover more about your problem and solution than you knew yesterday. I love Raibert's idea of a PRIZE_WINNING_STUFF.TXT file. I have a directory labeled playground/ where I place all the little snippets I've built as simple learning experiments, and now I think I need to create a winners/ directory right next to it!

Raibert closes with the advice to get feedback and then to trust your readers. A couple of months back I had a couple of entries on learning from critics, with different perspectives from Jerry Weinberg and Alistair Cockburn. That discussion was about text, not code (at least on the surface). But one thing that we in computer science need to do is to develop a stronger culture of peer review of our code. The lack of one is one of the things that most differentiates us from other engineering disciplines, to which many in computing look for inspiration. I myself look more to the creative disciplines for inspiration than to engineering, but on this the creative and engineering disciplines agree: getting feedback, using it to improve the work, and using it to improve the person who made the work are essential. I think that finding ways to work the evaluation of code into computer science courses, from intro courses to senior project courses, is a path to improving CS education.

PLoP 2007

This last bit of advice from Raibert is also timely, if bittersweet for me... In just a few days, PLoP 2007 begins. I am quite bummed that I won't be able to attend this year, due to work and teaching obligations. PLoP is still one of my favorite conferences. Patterns and writers' workshops are both close to my heart and my professional mind. If you have never written a software pattern or been to PLoP, you really should try both. You'll grow, if only when you learn how a culture of review and trust can change how you think about writing.

OOPSLA 2007

The good news for me is that OOPSLA 2007, which I will be attending, features a Mini-PLoP. This track consists of a pattern writing bootcamp, a writers' workshop for papers in software development, and a follow-up poster. I hope to attend the writers' workshop session on Monday, even if only as a non-author who pledges to read papers and provide feedback to authors. It's no substitute for PLoP, but it's one way to get the feeling.


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

August 28, 2007 9:44 PM

Refactoring, Beyond Software

Today I "refactored" the web page for a class session, along with files that support it. I used scare quotes there, but my process really was affected by the refactoring that we do to our code. I can probably describe it in terms of code refactorings.

Here is what I started with: a web page that loads thirteen images from a subdirectory named session02/, and a web page that loads two images from a subdirectory named session03/.

Due to changes in the timing of presentation, I needed to move a big chunk of HTML text from Session 3 to Session 2, including the text that loads the images from session03/.

In the old days, I would have cut the text from Session 3, pasted it into Session 2, renamed the images in session03/ so that they did not clash with files in session02/, moved them to session03/, and deleted session03/.

Along the way, there are a number of mistakes I could make, from inadvertently overwriting a file to losing text in transit by bungling a few keystrokes in emacs. I have done that before, and ended up spending precious time trying to recover the text and files I had lost.

I did something different this time. I didn't move and delete files or text. First, I copied text from one page to the other, allowing Session 2 to load images from the existing session03/ directory. I tested this change by loading the page to see that all the images still loaded in the right places. Only then did I delete the text from Session 2. Next, I copied the images from session03/ to session02/, using new names, and modified the web page to load the new images. I tested this change by re-loading the web page to verify the lecture. Only then did I delete session03/ and the images it contained.

Everything went smoothly. I felt so good that I even made a subdirectory named sample-compiler/ in the session02/ directory and moved the images in session02/ associated with the sample compiler -- one of the original session02/ images plus the two originally in session03/ -- down into the new subdirectory. I made this change in a similarly deliberate and safe way, making copies and running tests before removing any existing functionality.

When I got done, I felt as if I had applied to common code refactorings: Move Method and Extract Subclass. The steps were remarkably similar.

My description may sound as if this set of changes took me a long time to effect, but it didn't. Perhaps it took a few seconds longer than if I had executed a more direct path without error, but... I moved much more confidently in this approach, and I did not make any errors. The trade-off of deliberate action as insurance against the cost of recovering from errors was a net gain.

I refactored my document -- really, a complex of HTML files, subdirectories, and images -- using the steps like those we learn in Fowler and Kerievsky: small, seemingly too small in places, but guaranteed to work while "passing tests" along the way. My test, reloading the web page and examining the result after each small change, would be better if automated, but frankly the task here is simple enough the simple "inspect the output" method works just fine.

The ideas we discover in developing software often apply outside the world of software. I'm not sure this is an example of what people computational thinking, except in the broadest sense, but it is an example of how an idea we use in designing and implementing programs applies to the design and implementation of other artifacts. The ideas we discover in developing software often apply outside the world of software. We really should think about how to communicate them to the other folks who can use them.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

August 27, 2007 8:14 PM

All Out. All the Time.

Running on the university track late last week, I saw this slogan on the back of a student's T-shirt:

All out. All the time.

Such slogans are de rigeur for high school sports teams these days. They serve as mantras for the team, used to motivate the individual athlete but even more so to build team identity and spirit. I don't remember when I saw the first of these, but these days every team has one.

The folks at Despair.com have profited from pointing out how shallow and lame such slogans and motivational tools are. But I cut most of these T-shirts some slack, because they are aimed at kids, who are not perhaps at a deep level when it comes to motivation. I do hope that the involved coaches help their student-athletes move on to a deeper understanding of teams and motivation, both individual and group, than the slogans give.

But more importantly, I hope that these young athletes know that -- taken literally -- these slogans are usually wrong.

"All out. All the time." Any runner knows that this can't be true. If you run all out for any length of time, your body will let you know that won't be doing it all the time. Sprint 200 meters all out, and you'll need to recover. (Most coaches recommend at least 100m of recovery, or the same amount of time it took you to run the 200.) If you try to sprint 400 meters at the same pace that you can sprint 200 meters, then you'll usually fade fast at the end. Move all the way up to a marathon, and you have to make serious changes in your expected pace. That's just the our bodies work.

The same is true in any sport, along some dimension of exertion.

The same is also true in creative work. And in software development.

One of the great elements of Extreme Programming is the practice originally dubbed 40-hour work week and later renamed sustainable pace. Kent and Ward recognized that developers can't produce good code if they work beyond the pace that their minds and bodies allow. Ignoring those natural bounds is no different than trying to run your 200m pace for 400 or 800 or 1600 meters -- or for a marathon. If you try to go too fast for too long, you'll fade. That's not good for your client, and it's not good for developers.

There is a time for sprinting, surely, but software development and good relationships with customers are more of a long-term affair. Sprint in short bursts where that adds value for the customer and doesn't hurt the developers. But back off the throttle as a long-range plan.

The runners wearing slogans such as "All Out. All the Time." must know that they can't actually go all out all of the time. If they could, then I would never be able to pass them on the track with my tired old body, which most surely cannot go all out all of the time. But like them, I do like to go all out some of the time -- it feels good! And sometimes I myself will use even shallow, emotional sentiments to push myself when I am at the boundaries of what I think I can accomplish.

But then I take a recovery break.


Posted by Eugene Wallingford | Permalink | Categories: Running, Software Development

August 16, 2007 3:51 PM

Helping Developers Feel the Win of Agile Practices

Sometimes the best way to help someone learn a new habit is to let him or her feel the action happening, or not happening, in a new way. Sometimes, the action seems more natural when this feeling strikes a new chord.

I proposed an example of this approach many posts ago, in an entry called I Feel Good. I Feel Great. I Feel Wonderful. It reported an agile development fantasy I had after watching the Bill Murray flick What About Bob?. In my fantasy, I might use Dr. Leo Marvin's "Death Therapy" in an agile development scenario: Walk in one morning unannounced, and pull the plug on the project. An agile team should have something pretty reasonable to deliver. But would my students stone me before I could exit the room?

I managed to catch the beginning of a thread on the XP mailing list for once, a thread titled Your favorite teaching tricks?, launched by William Pietri. Unfortunately, this thread lasted only two messages, but both were valuable.

Pietri tells a story that displays one of his tricks for getting developers to write tests:

Friday night, I hung out with a pal who has been learning TDD. He is naturally full of questions, and one exchange went like this:

"If I have tested all the low-level methods, I don't need to test the components together, do I?"

"Did you run it to see if it worked?"

"Sure! I tried a few different options, and carefully looked at the output to be sure it was ok."

"If you had to check it, then you weren't sure it worked. Ergo, you should have written a test."

"Doh!"

Most developers already test in this way, writing simple little main programs that exercise their code. (Heaven help those who don't do at least this much -- and the people who use their code!) Why not automate that test? It's a small step from a handcrafted main to an xUnit test. And in my experience, that little main grows into an unmanageable mess. The xUnit test can grow gracefully into a suite of tests. (That doesn't mean you can't create an unmanageable mess, but at least we have a good book to help us get things right.) And from writing our post facto tests in xUnit, it's a somewhat larger but still small step to writing the test first.

J. B. Rainsberger followed up with a trick of his own, for working with customers:

I have one to help customers describe customer tests. If they seem not to want to do it, or have trouble, then when they ask me to build the feature, I immediately say "Done!"

They look puzzled. "You are not."

"Sure I am. Done!"

"You haven't done anything!"

"How do you know?"

The next thing out of their mouth is usually something we can easily turn into a customer test.

Very nice. I can't wait for one of my students to pull this on me for one of my underspecified assignments! Rainsberger does warn that this trick works best "only if you have a good personal relationship with the person acting as customer". So perhaps only those students who have developed a relationship of trust with me will want to venture this.

Of all the runaway threads on the XP list, this is one that I would like to have seen run longer. I'd love to hear others share some of their tricks at helping developers become more agile, whether in testing, pairing, refactoring, or any other practice.


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

July 26, 2007 1:21 PM

Agile Themes: Honesty and The Prime Directive

My last post looked at the relationship between honesty and blocking, motivated by a recent thread on the XP discussion list. In another thread, I encountered Dale Emery's message on The Prime Directive, and that got me to thinking about being honest with myself about my own behavior, and how to get better.

If you read much in the agile world, you'll run across the phrase "Prime Directive" a lot. I'm not a Trekkie, though I have enjoyed the several movies and TV series, but the first thing I think of when I hear the phrase is James T. Kirk. That's not what the agile folks are talking about... even if that directive raises interesting questions for a software person introducing agile methods to an organization!

If you google "prime directive agile", the first link is to Bob Martin's The Prime Directive of Agile Development, which is: Never be blocked. This is an ironic choice of words, given what I discussed in my previous post, but Martin is using an analogy from billiards, not football: An agile developer "makes sure that the shot he is taking sets up the next shot he expects to take.... A good agile developer never takes a step that stops his progress, or the progress of others." This is a useful notion, I think, but again not what most agilists mean when they speak of the Prime Directive.

They are referring instead to Norm Kerth's use of the phrase in the realm of project retrospectives, in which teams learn from the results of a recently-completed project in order to become a better team for future projects. Here is the Prime Directive for retrospectives, according to Norm:

The prime directive says:

Regardless of what we discover, we understand and truly believe that everyone did the best job they could, given what they knew at the time, their skills and abilities, the resources available, and the situation at hand.

At the end of a project everyone knows so much more. Naturally we will discover decisions and actions we wish we could do over. This is wisdom to be celebrated, not judgement used to embarrass.

This directive creates an environment in which people can examine past actions and results without fear of blame or reprisal. Instead the whole team can find ways to improve. When we look back at behavior and results in this context, we can be honest -- with our teammates and with ourselves. It's hard to improve oneself without facing the brutal facts that define our world and our person.

Emery's article focuses on the power of the phrase "given what they knew at the time". He does not view it as a built-in excuse -- well, I didn't know any better, so... -- rather as a challenge to identify and adjust the givens that limit us.

I apply The Prime Directive to my personal work by saying, "I did the best I could, given..." then fill in the givens. Then I set to work removing or relaxing the limiting conditions so that I perform better in the future. Usually, the most important conditions are the conditions within me, the conditions that I created.... If I created those conditions (and I did), then they are the conditions I can most directly improve.

Well said. Being honest with myself isn't easy, nor is following through on what I learn when I am. I take this as a personal challenge for the upcoming year.

(By the way, I strongly recommend Norm Kerth's book on retrospectives, as well as his pattern language on the transition from software analysis to design, Caterpillar's Fate. Norm is an engaging speaker and doer who celebrates the human element in whatever he touches. I reported on a talk he gave at PLoP 2004 on myth and patterns back in the early days of this blog.)


Posted by Eugene Wallingford | Permalink | Categories: General, Software Development

July 26, 2007 1:08 PM

Agile Themes: Honesty and Blocking

I recently wrote about a long-running thread on the XP discussion list about defining 'agile'. Another theme I've noticed across several threads is honesty. This entry and the one that follows look at two facets of the theme.

In one thread that seems to be dying down, the list has discussed the ethics of "blocking", a term that Scott Ambler borrowed from (American) football to describe teams that create the facade of following the official software development methodology while behind the scenes doing what they think is best to deliver the software. Scott wrote about this behavior, in which some members of the team protect the agile process by Running Interference for the rest of the team, in a 2003 Software Development article.

Is it right to do this? As developers, do we want to live our lives doing one thing and saying that we do another? I'm leery of any prescription that requires me to lie, yet I see shades of gray here. I don't think that my employer or our client are better served by actually following a process that is likely to fail to deliver the software as promised. Or, if my team is capable of delivering the software reasonably using the official methodology, then why do I need to lie in order to use an agile process? For me, programming in an agile way is a lot more fun, so there is that, but then maybe I need to find a place that will let me do that -- or start my own.

As I mentioned last time, I have not been able to follow the list discussion 100%, and I can't recall if Kent Beck ever chimed in. But I can imagine what he might say, given the substance and tone of his postings the last few years. If you have to lie -- even if we give it an innocuous name like "blocking"; even if we view it as a last resort -- then something is wrong, and you should think long and hard about how to make it right. Agile developers value people over processes, and honesty is one way we demonstrate that we value people.

George Dinwiddie has a blog entry that considered a more pragmatic potential problem with blocking. We may be getting the job done in the short term, but blocking is shortsighted and may hurt the agile cause in the long run. If we give the appearance of succeeding via the official route, our employer and customer are likely to conclude that the official route is a good one -- and that will make it even harder to introduce agile practices into the workplace. There is a practical value in telling the truth, even it requires us to take small steps. After all, agile developers ought to appreciate the power of small steps.


Posted by Eugene Wallingford | Permalink | Categories: General, Software Development

July 24, 2007 3:42 PM

Agile Themes: Defining Agile

Every so often the XP discussion list takes off in a frenzy of activity. The last few weeks have seen such a frenzy, which makes it difficult for readers like me to keep up. Fortunately, I am often able to find some nuggets of value with a two-pronged heuristic approach to reading: I usually home in on messages from a few folks whose posts I have found valuable in the past and scan the sub-threads that follow, and I occasionally select messages pseudo-randomly based on subject lines that tickle my fancy. I'm sure that I miss out on some valuable conversations along the way, but I do find enough to keep my wheels moving.

One long-running recent thread has focused on "defining agile" -- that is, being able to tell when an organization is using agile methods or not. If the list were made up solely of academics, this thread would be a natural. Academics love to put things into categories and name them. But this list is made up mostly of practitioners, and there interest in defining agile comes from many different directions, not the least of which is dispelling hype and distinguishing practices that help folks succeed.

I used to be much more dogmatic about naming things and separating methods and approaches and people into categories. A prime example was "real" object-oriented programming from the charade that some people display in a language that supports objects. Over time, I have soured of the battles and am more likely to espouse the point of view expressed by Andy Hunt somewhere back in the thread:

Instead of a test for agile, how about a test for "was your project a success or was it horked?" If it was a success, call it anything you want. If not, don't dare call it agile. :-)

This sort of pragmatism is reminiscent of Alan Turing's sidestepping of the question "what is intelligence?" in his seminal Computing Machinery and Intelligence. Such a definition makes it hard for agilists to defend their turf, but it lets folks who want to build systems get down to busy, rather than argue.

That said, I think that George Dinwiddie has done a nice job of capturing the essence of defining agile methods in a blog entry responding to the thread: using feedback that is frequent, timely, aligned with our desired goals, and pervasive. If you have read much of this blog, especially back in the first couple of years, you know that I have written frequently of the value of using feedback in many different circumstances, from developing software to teaching a class to training for and running a marathon. My appreciation of Dinwiddie's characterization is unsurprising.

Tim Haughton created a branch off this thread with a post that defines the Three Colours of Agile. Haughton reminds us that we need to tell different stories when we are dealing with the different parties involved in software projects. In particular, the customer who will use our software and the manager who oversees the development team have much different views on software development than the developers themselves have. Most of our discussion about agile methods focuses on the practices of developers and only peripherally with our interface to the rest of the world, if at all. Telling the right story at the right time can make a huge difference in whether another person buys into a new method proposed by developers. When we communicate the value of agile methods to the customer and manager from their perspective, the approach looks so much more palatable than a laundry list of developer practices they don't understand. Again, frequent readers of this blog will recognize a recurring theme of story telling.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

July 10, 2007 5:53 PM

Thinking Ahead to OOPSLA

OOPSLA 2007 logo

I haven't written much in anticipation of OOPSLA 2007, but not because I haven't been thinking about it. In years when I have had a role in content, such as the 2004 and 2005 Educators' Symposia or even the 2006 tutorials track, I have been excited to be deep in the ideas of a particular part of OOPSLA. This year I have blogged just once, about the December planning meeting. (I did write once from the spring planning meeting, but about a movies.) My work this year for the conference has been in an administrative role, as communications chair, which has focused on sessions and schedules and some web content. Too be honest, I haven't done a very good job so far, but that is a subject for another post. For now, let's just say that I have not been a very good Mediator nor a good Facade.

I am excited about some of the new things we are doing this year to get the word out about the conference. At the top of this list is a podcast. Now, podcasts have been around for a while now, but they are just now becoming a part of the promotional engine for many organizations. We figured that hearing about some of the cool stuff that will happen at OOPSLA this year would complement what you can read on the web. So we arranged to have two outfits, Software Engineering Radio and DimSumThinking, co-produce a series of episodes on some of the hot topics covered at this year's conference.

Our first episode, on a workshop titled No Silver Bullet: A Retrospective on the Essence and Accidents of Software Engineering, organized by Dennis Mancl, Steven Fraser, and Bill Opdyke, is on-line at the OOPSLA 2007 Podcast page. Stop by, give it a listen, and subscribe to the podcast's feed so that you don't miss any of the upcoming episodes. (We are available in iTunes, too.) We plan to role new interviews out every 7-10 for the next few months. Next up is a discussion of a Scala tutorial with Martin Odersky, due out on July 16.

If you would like to read a bit more about the conference, check out conference chair Richard Gabriel's The (Unofficial) How To Get Around OOPSLA Guide, and especially his ooPSLA Impressions. As I've written a few times, there really isn't another conference like OOPSLA. Richard's impressions page does a good job communicating just how, mostly in the words of people who've been to OOPSLA and seen it.

While putting together some of his podcast episodes, Daniel Steinberg of DimSumThinking ran into something different than usual: fun.

I've done three interviews for the oopsla podcast -- every interviewee has used the same word to describe OOPSLA: fun. I just thought that was notable -- I do a lot of this sort of thing and that's not generally a word that comes up to describe conferences.

And that fun comes on top of the ideas and the people you will encounter, that will stretch you. We can't offer a Turing Award winner every year, but you may not notice with all the intellectual foment. (And this year, we can offer John McCarthy as an invited speaker...)


Posted by Eugene Wallingford | Permalink | Categories: Computing, Patterns, Software Development

July 09, 2007 7:28 PM

Preparing for Fall Compilers Course (Almost)

Summer is more than half over. I had planned by now to be deep in planning for my fall compilers course, but the other work has kept me busy. I have to admit also to suffering from a bout of intellectual hooky. Summer is a good time for a little of that.

Compilers is a great course, in so many ways. It is one of the few courses of an undergraduate's curriculum in which students live long enough with code that is big enough to come face-to-face with technical debt. Design matters, implementation matters, efficiency matters. Refactoring matters. The course brings together all of the strands of the curriculum into a real project that requires knowledge from the metal up to the abstraction of language.

In the last few weeks I've run across several comments from professional developers extolling the virtues of taking a compilers course, and often lamenting that too many schools no longer require compilers for graduation. We are one such school; compilers is a project option competing with several others. Most of the others are perceived to be easier, and they probably are. But few of the others offer anything close to the sort of capstone experience that compilers does.

In a comment on this post titled Three Things I Learned About Software in College, Robert Blum writes:

Building OSes and building compilers are the two ends of the spectrum of applied CS. Learn about both, and you'll be able to solve most problems coming your way.

I agree, but a compilers course can also illuminate theoretical CS in ways that other courses don't. Many of the neat ideas that undergrads learn in an intro theory course show up in the first half of compilers, where we examine grammars and build scanners and parsers.

My favorite recent piece on compilers is ultra-cool Steve Yegge's Rich Programmer Food. You have to read this one -- promise me! -- but I will tease you with Yegge's own precis:

Gentle, yet insistent executive summary: If you don't know how compilers work, then you don't know how computers work. If you're not 100% sure whether you know how compilers work, then you don't know how they work.

Yegge's article is long but well worth the read.

As for my particular course, I face many of the same issues I faced the last time I taught it: choosing a good textbook, choosing a good source language, and deciding whether to use a parser generator for the main project are three big ones. If you have any suggestions, I'd love to hear from you. I'd like to build a larger, more complete compiler for my students to have as a reading example, and writing one would be the most fun I could have getting ready for the course.

I do think that I'll pay more explicit attention in class to refactoring and other practical ideas for writing a big program this semester. The extreme-agile idea of 15 compilers in 15 days, or something similar, still holds me in fascination, but at this point I'm in love more with the idea than with the execution, because I'm not sure I'm ready to do it well. And if I can't do it well, I don't want to do it at all. This course is too valuable -- and too much fun -- to risk on an experiment in whose outcome I don't have enough confidence.

I'm also as excited about teaching the course as the last time I taught it. On a real project of this depth and breadth, students have a chance to take what they have learned to a new level:

How lasts about five years, but why is forever.

(I first saw that line in Jeff Atwood's article Why Is Forever. I'm not sure I believe that understanding why is a right-brain attribute, but I do believe in the spirit of this assertion.)


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

July 07, 2007 7:10 AM

Quick Hits, Saturday Edition

Don't believe me about computational processes occurring in nature? Check out Clocking In And Out Of Gene Expression, via The Geomblog. Some genes turn other genes on and off. To mark time, they maintain a clock by adding ubiquitin molecules to a chain; when the chain reaches a length of five, the protein is destroyed. That sounds a lot like a Turing machine using a separate tape as a counter...

Becky Hirta learned something that should make all of us feel either better or worse: basic math skills are weak everywhere. We can feel better because it's not just our students, or we can feel worse because almost no one can do basic math. One need not be able to solve solve linear equations to learn how to write most software, but an inability to learn how to solve solve linear equations doesn't bode well.

Hey, I made the latest Carnival of the Agilists. The Carnival dubs itself "the bi-weekly blogroll that takes a sideways slice through the agile blogosphere". It's a nice way for me to find links to articles on agile software development that I might otherwise have missed.


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

June 22, 2007 4:32 PM

XUnit Test Patterns and the Duplex Book

Several folks have already recommended Gerard Meszaros's new book, xUnit Test Patterns. I was fortunate to have a chance to review early drafts of Gerard's pattern language on the web and then at PLoP 2004, where Gerard and I were in a writers' workshop together. By that time I felt I knew a little about writing tests and using JUnit, but reading Gerard's papers that fall taught me just how much more there was for me to learn. I learned a lot that month and can only hope that my participation in the workshop helped Gerard a small fraction as much as his book has helped me. I strongly echo Michael Feathers's recommendation: "XUnit Patterns is a great all around reference." (The same can be said for Michael's book, though my involvement reviewing early versions of it was not nearly as deep.)

As I grow older, I have a growing preference for short books. Maybe I am getting lazy, or maybe I've come to realize that most of the reasons for which I read don't require 400 or 600 hundred words. Gerard's book weighs in at a hefty 883 pages -- what gives? Well, as Martin Fowler writes in his post Duplex Book, XUnit Test Patterns is really more than one book. Martin says two, but I think of it as really three:

  • a 181-page narrative that teaches us about automated tests, how to write them, and how to refactor them,
  • a 91-page catalog of smells you will find in test code, and
  • an approximately 500-page catalog of the patterns of test automation. These patterns reference one another in a tight network, and so might be considered a pattern language.

So in a book like this, I have the best of two worlds: a relatively short, concise, well-written story that shows me the landscape of automated unit testing and gets me started writing tests, plus a complete reference book to which I can turn as I need to learn a particular technique in greater detail. I can read the story straight through and then jump into and out of the catalogs as needed. The only downside is the actual weight of the book... It's no pocket reference! But that's a price I am happy to pay.

One of my longstanding goals has been to write an introductory programming textbook, say for CS1, in the duplex style. I'm thinking something like the dual The Timeless Way of Building/A Pattern Language, only shorter and less mystical. I had always hoped to be the first to do this, to demonstrate what I think is a better future for instructional books. But at this increasingly late date, I'd be happy if anyone could succeed with the idea.


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

June 18, 2007 4:18 PM

What is the Simplest Thing?

Tim Ottinger recently posted a blog entry on a problem that we all face: how to know what the simplest thing is when tying to do the simplest thing. Tim points out that what he finds simple may not match at all what others find simple, and vice versa. This is a problem whenever we are working collaboratively, because our decision becomes part of the common code base that everyone works with. But I think it's also a problem for solo programmers who want to remain true to the spirit of YAGNI and reap the benefits offered by growing a program organically in small steps.

When I face this decision in my individual programming, I try to make the choice between two potential implementations based on the sheer effort I have to make today to make my program run with the new feature in it. This means ignoring the voice in my head that says, "But you know that later you'll have to change that." Well, okay then, I'll change it later. The funny thing is that sometimes, I don't have to change it later, at least not in the way I thought back then.

Below a certain threshold of time and energy, I treat all effort as roughly the same. Often, one approach uses a base data type and the other uses a simple object that hides the base data type. I can often implement the former a small bit faster, but I can usually implement both quickly enough to have my feature running now. In such cases, I will usually opt for the object. Maybe this violates the spirit of doing the simplest thing that could possibly work, but I don't find that to be the case in practice. Even when I am wrong and make a change later, it is almost never to retract my object but to change the object's implementation. I almost always want my program to speak in the language of the problem domain, not the underlying programming language, and the object enables my program to do that. In this sense, my experience gibes with that of Kevin Lawrence, who coined an eponymous maxim to address a similar case:

If you ever feel yourself drawn toward writing a static method, obey Kevin's Maxim: "in an object-oriented language the simplest thing that could possibly work is an object."

The key is that we seek to defer non-trivial programming effort until the time spent making it will prove valuable in today's version of the system.

Whenever pair programming is involved, the desire to do the simplest thing becomes the subject of a pairwise conversation. And as pairs form and dissolve over time, the group's collective wisdom can become part of the decision-making process. The goal of focusing the time spent of delivering value today remains the same, but now we can draw on more experience in making the decision.

Ultimately, I think the value in having YAGNI and Do the Simplest Thing that Could Possibly Work as goals comes back to something that came up in my last post. The value of these guidelines comes not from the specific answers we come up with but from the fact that we are asking the questions at all. At least we are thinking about giving our customer fair value for the work we are doing today, and trying to keep our program simple enough that we can grow them honestly over time. With those goals in mind, we will usually be doing right by our customers and ourselves. We will grow wiser over time as to what is simplest in our problem domain, in our programming milieu, and for us as developers. As a result, we ought to be able to give even better answers in the future.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

June 13, 2007 4:05 PM

BASIC and COBOL Cross My Path

I don't run into Basic and Cobol all that often these days, but lately they seem to pop up all over. Once recently I even ran into them together in an article by Tim Bray on trends in programming language publishing:

Are there any here that might go away? The only one that feels threatened at all is VB, wounded perhaps fatally in the ungraceful transition to .NET. I suppose it's unlikely that many people would pick VB for significant new applications. Perhaps it's the closest to being this millennium's COBOL; still being used a whole lot, but not creatively.

Those are harsh words, but I suppose it's true that Cobol is no longer used "creatively". But we still receive huge call for Cobol instruction from industry, both companies that typically recruit our students and companies in the larger region -- Minneapolis, Kansas City, etc. -- who have learned that we have a Cobol course on the books. Even with industry involvement, there is effectively no student demand for the course. Whether VB is traveling the same path, I don't know. Right now, there is still decent demand for VB from students and industry.

Yesterday, I ran into both languages again, in a cool way... A reader and former student pointed out that I had "hit the big leagues" when my recent post on Alan Kay started scoring points at programming.reddit.com. When I went there for a vanity stroke, I ran into something even better, a Sudoku solver written in Cobol! Programmers are a rare and wonderful breed. Thanks to Bill Price for sharing it with us. [1]

While looking for a Cobol compiler for my Intel Mac [2], I ran instead into Chipmunk Basic, "an old-fashioned Basic interpreter" for Mac OS. This brings back great memories, especially in light of my upcoming 25th high school reunion. (I learned Basic as a junior, in the fall of 1980.) Chipmunk Basic doesn't seem to handle my old graphics-enabled programs, but it runs most of the programs my students wrote back in the early 1990s. Nice.

I've been considering a Basic-like language as a possible source language for my compiler students this fall. I first began having such thoughts when I read a special section on lightweight languages in a 2005 issue of Dr. Dobbs' Journal and found Tom Pitman's article The Return of Tiny Basic. Basic has certain limitations for teaching compilers, but it would be simple enough to tackle in full within a semester. It might also be nice for historical reasons, to expose today's students to something that opened the door to so many CS students for so many years.

----

[1] I spent a few minutes poking around Mr. Price's website. In some sort of cosmic coincidence, it seems that Mr. Price is took his undergraduate degree at the university where I teach (he's an Iowa native), and is an avid chessplayer -- not to mention a computer programmer! That's a lot of intersection with my life.

[2] I couldn't find a binary for a Mac OS X Cobol, only sources for OpenCOBOL. Building this requires building some extension packages that don't compile without a bunch of tinkering, and I ran out of time. If anyone knows of a decent binary package somewhere, please drop me a line.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Personal, Software Development

June 12, 2007 1:38 PM

Trying to Learn from All Critics

Without having comments enabled on my blog, I miss out on most of the feedback that readers might like to give. It seems like a bigger deal to send an e-mail message with comments. Fortunately for me, a few readers go out of their way to send me comments. Unfortunately for the rest of my readers, those comments don't make it back into the blog the way on-line comments do, and so we all miss out on the sort of conversation that a blog can generate. I think it's time to upgrade my blogging software, I think...

Alistair Cockburn recently sent a comment on my entry But Raise Your Hand First that I must share (with Alistair's permission, of course):

Contrary to Weinberg, I use the exact opposite evaluation of a critic's comments: I assume that anybody, however naive and unschooled, has a valid opinion. No matter what they say, how outrageous, how seemingly ill-founded, someone thought it true, and therefore it is my job to examine it from every presupposition, to discover how to improve the <whatever it is>. I couldn't imagine reducing valid criticism to only those who have what I choose to call "credentials". Just among other things, the <whatever it is> improves a lot faster using my test for validity.

This raises an important point. I suspect that Weinberg developed his advice while thinking about one's inner critics, that four-year-old inside our heads. When he expressed it as applying to outer critics, he may well still have been in the mode of protecting the writer from prior censorship. But that's not what he said.

I agree with Alistair's idea that we should be open to learning from everyone, which was part of the reason I suggested that students not use this as an opportunity to dismiss critique from professors. When students are receiving more criticism than they are used to, it's too easy to fall into the trap of blaming the messenger rather than considering how to improve. I think that most of us, in most situations, are much better served by adopting the stance, "What can I learn from this?" Alistair said it better.

But in the border cases I think that Alistair's position places a heavy and probably unreasonable burden on the writer: "... my job to examine it from every presupposition, to discover how to improve the <whatever it is>." That is a big order. Some criticism is ill-founded, or given with ill will. When it is, the writer is better off to turn her attention to more constructive pursuits. The goal is to make the work better and to become a better writer. Critics who don't start in good faith or who lie too far from the target audience in level of understanding may not be able to help much.


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

June 11, 2007 4:31 PM

Alan Kay's "The Reactive Engine"

Last week I somehow came across a pointer to Matthias Müller-Prove's excerpt of "The Reactive Engine", Alan Kay's 1969 Ph.D. thesis at the University of Utah. What a neat find! The page lists the full table of contents and gives then gives the abstract and a few short passages from the first section on FLEX, his hardware-interpreted interactive language that foreshadows Smalltalk.

Those of you who have read here for a while know that I am a big fan of Kay's work and often cite his ideas about programming as a medium for expressing and creating thought. One of my most popular entries is a summary of his Turing Award talks at the 2004 OOSPLA Educators' Symposium. It is neat to see the roots of his recent work in a thesis he wrote nearly forty years ago, a work whose ambition, breadth, and depth seem shocking in a day where advances in computing tend toward the narrow and the technical. Even then, though, he observed this phenomenon: "Machines which do one thing only are boring, yet exert a terrible fascination." His goal was to construct a system that would serve as a medium for expression, not just be a special-purpose calculator of sorts.

The excerpt that jarred me most when I read it was this statement of the basic principles of his thesis:

Probably the two greatest discoveries to be made [by pre-literate man] were the importance of position in a series of grunts, and that one grunt could abbreviate a series of grunts. Those two principles, called syntax (or form) and abstraction, are the essence of this work.

In this passage Kay ties the essential nature of computing back to its source in man's discovery of language.

In these short excerpts, one sees the Alan Kay whose manner of talking about computing is delightfully his own. For example, on the need for structure in language:

The initial delights of the strongly interactive languages JOSS and CAL have hidden edges to them. Any problem not involving reasonably simple arithmetic calculations quickly developed unlimited amounts of "hair".

I think we all know just what he means by this colorful phrase! Or consider his comments on LISP and TRAC. These languages were notable exceptions to the sort of interactive language in existence at the time, which left the user fundamentally outside of the models they expressed. LISP and TRAC were "'homoiconic', in that their internal and external representations are essentially the same". (*) Yet these languages were not sufficient for Kay's goal of making programming acceptable to any person interested in entering a dialog with his system:

Their only great drawback is that programs written in them look like King Burniburiach's letter to the Sumerians done in Babylonian cun[e]iform!

Near the end of his introduction to FLEX Kay describes the goals for the work documented in the thesis (bolded text is my emphasis):

The summer of 1969 sees another FLEX (and another machine). The goals have not changed. The desire is still to design an interactive tool which can aid in the visualization and realization of provocative notions. It must be simple enough so that one does not have to become a systems programmer (one who understands the arcane rites) to use it. ... It must do more than just be able to realize computable functions; it has to be able to form the abstractions in which the user deals.

The "visualization and realization of provocative notions"... not just by those of us who have been admitted to the guild of programmers, but everyone. That is the ultimate promise -- and responsibility -- of computing.

Kay reported then that "These goals have not been reached." Sadly, forty years later, we still haven't reached them, though he and his team continue to work in this vein. His lament back in 2004 was that too few of us had joined in the search, settling instead to focus on what will in a few decades -- or maybe even five years -- be forgotten as minutiae. Even folks who thought they were on the path had succumbed to locking in to vision of Smalltalk that is now over twenty-five years old, and which Kay himself knows to be just a stepping stone early on the journey.

In some ways, this web page is only a tease. I really should obtain a copy of his full thesis and read it. But Matthias has done a nice job pulling out some of the highlights of the thesis and giving us a glimpse of what Alan Kay was thinking back before our computers could implement even a small bit of his vision. Reading the excerpt was at once a history lesson and a motivating experience.

----

(*) Ah, that's where I ran across the link to this thesis, in a mailing-list message that used the term "homoiconic" and linked to the excerpt.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

June 05, 2007 8:11 AM

Miscellaneous Thoughts for Programmers

As summer begins for me, I get to think more about programming. For me, that will be Ruby and my compilers over the next few months.

Too Hard

From Ruby vs. Java Myth #3:

In what serious discipline is "It's too hard" a legitimate excuse? I have never seen a bank that eschews multiplication: "We use repeated addition here--multiplication was too hard for our junior staffers." And I would be uncomfortable if my surgeon said, "I refuse to perform procedures developed in the last 10 years--it is just too hard for me to learn new techniques."

Priceless. This retort applies to many of our great high-level languages, such as Scheme or Haskell, as anyone who has taught these languages will attest.

The problem we in software have is this conundrum: The level of hardness -- usually, abstraction -- we find in some programming languages narrows our target population much more than the level of hardness that we find in multiplication. At the same time, our demand for software developers far outstrips our demand for surgeons. Finding ways to counteract these competing forces is a major challenge for the software industry and for computing programs.

For what it's worth, I strongly second Stuart's comments in Ruby vs. Java Myth #1, on big and small projects. This is a case where conventional wisdom gets things backwards, at a great cost to many teams.

A Programmer's Programmer

I recently ran across a link to this interview with Don Knuth from last year. It's worth a read. You gotta love Knuth as much as you respect his work:

In retirement, he still writes several programs a week.

Programmers love to program and just have to do it. But even with 40+ years of experience, Knuth admits a weakness:

"If I had been good at making estimates of how long something was going to take, I never would have started."

If you've studied AI or search algorithms, you from A* that underestimates are better than overestimates, for almost exactly the reason that they helped Knuth. There are computational reasons this is true for A*, but with people it is mostly a matter of psychology -- humans are more likely to begin a big job if they start with a cocky underestimate. "Sure, no problem!"

If you are an agile developer, Knuth's admission should help you feel free not to be perfect with your estimates; even the best programmers are often wrong. But do stay agile and work on small, frequent releases... The agile approach requires short-term estimates, which can be only so far off and which allow you to learn about your current project more frequently. I do not recommend underestimates as drastic as the ones Knuth made on his typesetting project (which ballooned to ten years) or his Art of Computing Programming series (at nearly forty years and counting!) A great one like Knuth may be creating value all the long while, but I don't trust myself to be correspondingly productive for my clients.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

June 04, 2007 8:22 AM

A Blog Entry From Before I Had a Blog #2

[ UPDATE: I have corrected the quote of Alistair Cockburn that leads below. I'm sure Kent gave the right quote in his talk, and my notes were in error. The correct quote makes more sense in context. Thanks, Alistair. ]

Back in March 2006, I posted notes on an OOPSLA 2003 invited talk by David Ungar. While plowing through some old files last week, I found notes from another old OOPSLA invited talk, this from 2002: Kent Beck's "The Metaphor Metaphor". I've always appreciated Kent's person-centered view of software development, and I remember enjoying this talk. These notes are really a collection of snippets that deal with how language matters in how we think about our projects.

Kent Beck

The Metaphor Metaphor, by Kent Beck

November 6, 2002

"Embellishment is the pitfall of the methodologist." (Alistair Cockburn)

You gain experience. You are asked for advice. You give advice. They ask for more. Eventually, you reach the end of your experience. You run out of advice to give. But you don't run out of people asking you for advice. So, you reach...

Stupid ideas are important. How else will you know that the clever ideas are clever? Don't be afraid of stupid ideas.

A trope is an expression whose meaning is not intended to be derived from the literal interpretation of its words. There are many kinds of trope:

  • irony: spoken such that the opposite is true
  • paralipsis: speaking to a subject by saying that you won't
  • hyperbole: excessive exaggeration
  • pun: using word sounds to create ambiguity
  • metonymy: refer to the whole by referring to a part or a role
  • simile: explicit comparison
  • analogy: simile with connections among the parts
  • metaphor: the linkages plus the concomitant understanding that results

Think about how much of our communication is tropic. Is this a sign that our words and tools are insufficient for communication, or a sign that communication is really hard? (Kent thinks both.)

A key to the value of metaphor is the play between is and is not. How a metaphor holds and how it doesn't both tell us something valuable.

Metaphors run deep in computing. An example: "This is a memory cell containing a 1 or a 0." All four underlined phrases are metaphorical!

Kent's college roommate used to say, "Everything is an interpreter."

Some metaphors mislead. "war on terrorism" is a bad metaphor. "war on disease (e.g., cancer)" is a bad metaphor. Perhaps "terrorism is a disease" is a better metaphor!?

Lakoff's Grounding Hypothesis states: All metaphors ground in physical reality and experience. [Kent gave an example using arithmetic and number lines, relating to an experiment with children, but my notes are incomplete.]

We made Hot Draw "before there were computers". This meant that doing graphics "took forever". Boy was that fun! One cool thing about graphics programming: your mistakes look so interesting!

Hot Draw's metaphors: DRAWING +

  • FIGURE
  • TOOL
  • HANDLE

A lot of good design is waiting productively.

Regarding this quote, Kent told a story about duplicating code -- copy-and-paste with changes to two lines -- and not removing it. That's completely different from copying and pasting code with changes to two lines and not removing. [This is, I think, a nod to the old AI koan (listed first here) about toggling the on/off switch of a hung computer to make it work...]

Kent's final recommendations:

  • Be aware of computing's metaphors -- and your own!
  • If the Grounding Hypothesis is correct, then more physical activity makes better programmers. (Or at least ones with more interesting things to talk about.)

[end of excerpt]

That last recommendation reflects a truth that people often forget: Well-rounded people bring all sorts of positives, obvious and less so, to programming. And I love the quote about design as "productive waiting".

As with any of my conference reports, the ideas presented belong to Kent unless stated otherwise, but any mistakes are mine. With a five-year-old memory of the talk, mistakes in the details are probably unavoidable...


Posted by Eugene Wallingford | Permalink | Categories: General, Software Development

May 30, 2007 4:27 PM

But Raise Your Hand First

Weinberg on assessing the value of a critic's comments:

Here's an excellent test to perform before listening to any critic, inside or outside:

What have they written that shows they have the credentials to justify the worth of their criticism?

This test excludes most high-school and college teachers of English, most of your friends, lots of editors and agents, and your mother.

It also excludes your [inner] four-year-old, who's never written anything.

Computer science students should show due respect to their professors (please!), but they might take this advice to heart when deciding how deeply to take criticism of their writing -- their programs. Your goal in a course is to learn something, and the professor's job is to help you. But ultimately you are responsible for what you learn, and it's important to realize that the prof's evaluation is just one -- often very good -- source. Listen, try to decide what is most valuable, learn, and move on. You'll start to develop your own tastes and skills that are independent of your the instructors criticism.

Weinberg's advice is more specific. If the critic has never written anything that justifies the worth of their criticism, then the criticism may not be all that valuable. I've written before about the relevance of a CS Ph.D. to teaching software development. Most CS professors have written a fair amount of code in their days, and some have substantial industry experience. A few continue to program whenever they can. But frankly some CS profs don't write much code in their current jobs, and a small group have never written any substantial program. As sad as it is for me to say, those are the folks whose criticism you sometimes simply have to take with a grain of salt when you are learning from them.

The problem for students is that they are not ideally situated to decide whose criticism is worth acting on. Looking for evidence is a good first step. Students are also not ideally situated to evaluate the quality of the evidence, so some caution is in order.

Weinberg's advice reminds me of something Brian Marick said, on a panel at the OOPSLA'05 Educators' Symposium. He suggested that no one be allowed to teach university computer science (or was it software development?) unless said person had been a significant contributor to an open-source software project. I think his motivation is similar to what Weinberg suggests, only broader. Not only should we consider someone's experience when assessing the value of that person's criticism, we should also consider the person's experience when assessing the value of what they are able to teach us.

Of course, you should temper this advice as well with a little caution. Even when you don't have handy evidence, that doesn't mean the evidence doesn't exist. Even if no evidence exists, that doesn't mean you have nothing to learn from the person. The most productive learners find ways to learn whatever their circumstances. Don't close the door on a chance to learn just because of some good advice.

So, I've managed to bring earlier threads together involving Brian Marick and Gerald Weinberg, with a passing reference to Elvis Costello to boot. That will have to do for closure. (It may also boost Brian's ego a bit.)


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

May 22, 2007 3:55 PM

Someone Competent to Write Code

Students sometimes say to me:

I don't have to be good at <fill in the blank>. I'll be working on a team.

The implication is that the student can be good enough at one something and thus not have to get good at some other part of the discipline. Usually the skill they want to depend is a softer skill, such as communication or analysis, The skill they want to avoid mastering is something they find harder, usually a technical skill and -- all too often -- programming.

First, let me stipulate that not everyone master every part of computer science of software development. But this attitude usually makes some big assumptions about whether a company should want to entrust systems analysis or even "just" interacting with clients. I always tell students that many people probably won't want them on their teams if they aren't at least competent at all phases of the job. You don't have to great at <fill in the blank>, or everything, but you do have to be competent.

I was reminded of this idea, which I've talked about here at least once before when I ran across Brian Marick quoting an unnamed programmer:

What should teams do with the time they're not spending going too fast? They should invest in one of the four values I want to talk about: skill. As someone who wants to remain anonymous said to me:

I've also been tired for years of software people who seem embarrassed to admit that, at some point in the proceedings, someone competent has to write some damn code.

He's a programmer.

This doesn't preclude specialization. Maybe each team has one someone competent has to write some damn code. But most programmers who have been in the trenches are skeptical of working with teammates who don't understand what it's like to deliver code. Those teammates can make promises to customers that can't be met, and "design system architectures" that are goofy at best and unimplementable at worst.

One of the things I like about the agile methods is that they try to keep all of the phases of software development in focus at once, on roughly an even keel. That's not how some people paint Agile when they talk it down, but it is one of the critical features I've always appreciated. And I like how everyone is supposed to be able to contribute in all phases -- not as masters, necessatily, but as competent members of the team.

This is one of the ideas that Brian addresses in the linked-to article, which talks about the challenge facing proponents of so-called agile software development in an age when execution is more important than adoption. As always, Brian writes a compelling story. Read it. And if you aren't already following his blog in its new location, you should be.


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

May 21, 2007 4:45 PM

More on Metaphors for Refactoring

Not enough gets said about the importance of abandoning crap.

-- Ira Glass
, at Presentation Zen

Keith Ray wrote a couple of entries last month on refactoring. The first used the metaphor of technical debt and bankruptcy. The second used the simile of refactoring as like steering a car.

In my experience and that of others I've read, the technical debt metaphor works well with businesspeople. It fits well into their world view and uses the language that they use to understand their business situation. But as I wrote earlier, I don't find that this works all that well with students. They don't live in the same linguistic and experiential framework as businesspeople, and the way people typically perceive risk biases them against being persuaded.

A few years ago Owen Astrachan, Robert Duvall, and I wrote a paper called Bringing Extreme Programming to the Classroom that originally appeared at XP Universe 2001 and was revised for inclusion in Extreme Programming Perspectives. In that paper, we described some of the micro-examples we used at that time to introduce refactoring to novice students. My experience up to then and since has been that students get the idea and love the "a-a-a-ahhh" that comes from a well-timed refactor, but that most students do not adopt the new practice as a matter of course. When they get into the heat of a large project, they either try to design everything up front (and usually guess wrong, of course) or figure they can always make do with whatever design they currently have, whether designed or accreted.

Students simply don't live with most code long enough, even on a semester-long project, to come face-to-face with technical bankruptcy. When they, they declare it and make do. I think in my compilers course this fall I'm going to try to watch for the first opportunity to help one of the student groups regain control of their project through refactoring, perhaps even as a demonstration for the whole class. Maybe that will work better.

That said, I think that Ray's steering wheel analogy may well work better for students than the debt metaphor. Driving is an integral part of most students' lives, and maybe we can connect to their ongoing narratives in this way. But the metaphor will still have to be backed up with a lot of concrete practice that helps them make recognizable progress. So watching for an opportunity to do some macro-level refactoring is still a good idea.

Another spoke in this wheel is helping students adopt the other agile practices that integrate so nicely with refactoring. As Brian Marick said recently in pointing out values missing from the Agile Manifesto,

Maybe the key driver of discipline is the practice of creating working software -- running, tested features -- at frequent intervals. If you're doing that, you just don't have time for sloppiness. You have to execute well.

But discipline -- especially discipline that conflicts with one's natural, internal, subconscious biases -- is hard to sell. In a semester-long course, by the time students realize they really did need that discipline, time is too short to recover properly. They need time to ingrain new practice as habit. For me as instructor, the key is "small", simple practices that people can do without high discipline, perhaps with some external guidance until their new habit forms. Short iterations are something I can implement as an instructor, and with enough attention paid throughout the term and enough effort exerted at just the right moments, I think I can make some headway.

Of course, as Keith reminds us and as we should always remember when trafficking in metaphor: "Like all analogies, there's a nugget of truth here, but don't take the analogy too far."


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

May 20, 2007 3:14 PM

Good and Bad Use

Recently I wrote about persuasion and teaching, in light of what we know about how humans perceive and react to risk and new information. But isn't marketing inherently evil, in being motivated by the seller's self-interest and not the buyer's, and thus incompatible with a teacher/student relationship? No.

First of all, we can use an idea associated with a "bad" use to achieve something good. Brian Marick points out that the motivating forces of XP are built in large part on peer pressure:

Some of XP's practices help with discipline. Pair programming turns what could be a solitary vice into a social act: you and your pair have to look at each other and acknowledge that you're about to cheat. Peer pressure comes into play, as it does because of collective code ownership. Someone will notice the missing tests someday, and they might know it was your fault.

This isn't unusual. A lot of social organizations provide a former of positive peer pressure to help individuals become better, and to create a group that adds value to the world. Alcoholics Anonymous is an example for people tempted to do something they know will hurt them; groups of runners training for a marathon rely on one another for the push they need to train on days they feel like not and to exert the extra effort they need to improve. Peer pressure isn't a bad thing; it's just depends on who you choose for your peers.

Returning to the marketing world, reader Kevin Greer sent me a short story on something he learned from an IBM sales trainee:

The best sales guy that I ever worked with once told me that when he received sales training from IBM, he was told to make sure that he always repeated the key points six times. I always thought that six times was overkill but I guess IBM must know what they're talking about. A salesman is someone whose income is directly tied to their ability to effectively "educate" their audience.

What we learn here is not anything to do with the salesman's motive, but with the technique. It is grounded in experience. Teachers have heard this advice in a different adage about how to structure a talk: "Tell them what you are about to tell them. Then tell them. Then tell them what you have just told them." Like Kevin, I felt this was overkill when I first heard it, and I still rarely follow the advice. But I do know from experience how valuable it can be me, and in the meantime I've learned that how the brain works makes it almost necessary.

While I'm still not a salesman at heart, I've come to see how "selling" an idea in class isn't a bad idea. Steve Pavlina describes what he calls marketing from your conscience. His point ought not seem radical: "marketing can be done much more effectively when it's fully aligned (i.e., congruent) with one's conscience."

Good teaching is not about delusion but about conscience. It is sad that we are all supposed to believe the cynical interpretation of selling, advertising, and marketing. Even in the tech world we certainly have plenty of salient reasons to be cynical. We've all observed near-religious zealotry in promoting a particular programming language, or a programming style, or a development methodology. When we see folks shamelessly shilling the latest silver bullet as a way to boost their consulting income, they stand out in our minds and give us a bad taste for promotion. (Do you recognize this as a form of the availability heuristic?)

But.

I have to overcome my confirmation bias, other heuristic biases that limit my thinking, and my own self-interest in order to get students and customers to gain the knowledge that will help them; to try new languages, programming styles, and development practices that can improve their lives. What they do with these is up to them, but I have a responsibility to expose them to these ideas, to help them appreciate them, to empower them to make informed choices in their professional (and personal!) lives. I can't control how people will use the new ideas they learn with me, or if they will use them at all, but if help them also to learn how to make informed choices later, then I've done about the best I can do. And not teaching them anything isn't a better alternative.

I became a researcher and scholar because I love knowledge and what it means for people and the world. How could I not want to use my understanding of how people learn and think to help them learn and think better, more satisfyingly?


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

May 17, 2007 11:08 AM

Quick Hits

Over the last couple of months, I've been collecting some good lines and links to the articles that contain them. Some of these may show up someday in something I write, but it seems a shame to have them lie fallow in a text file until then. Besides, my blog often serves as my commonplace book these days. All of these pieces are worth reading for more than the quote.

If the code cannot express itself, then a comment might be acceptable. If the code does not express itself, the code should be fixed.
-- Tim Ottinger, Comments Again

In a concurrent world, imperative is the wrong default!
-- Tim Sweeney of Epic Games, The Next Mainstream Programming Language: A Game Developer's Perspective, an invited talk at ACM POPL'06 (full slides in PDF)

When you are tempted to encode data structure in a variable name (e.g. Hungarian notation), you need to create an object that hides that structure and exposes behavior.
-- Uncle Bob Martin The Hungarian Abhorrence Principle

Lisp... if you don't like the syntax, write your own.
-- Gordon Weakliem, Hashed Thoughts, on simple syntax for complex data structures

Pairing is a practice that has (IIRC) at least five different benefits. If you can't pair, then you need to find somewhere else in the process to put those benefits.
-- John Roth, on the XP mailing list

Fumbling with the gear is the telltale sign that I'm out of practice with my craft. ... And day by day, the enjoyment of the craft is replaced by the tedium of work.
-- Mike Clark, Practice

So when you get rejected by investors, don't think "we suck," but instead ask "do we suck?" Rejection is a question, not an answer.
-- Paul Graham, The Hacker's Guide to Investors

Practice. Question rejection.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Personal, Software Development

May 16, 2007 3:53 PM

All About Stories

Telling Stories, by Garmash

I find it interesting that part of what I learned again from Schneier's psych of risk paper leads to stories. But biases in how we think, such as availability and framing, make the stories we tell important -- if we want them to reach our audience as intended. Then again, perhaps my direction in this series follows from a bias in my own mind: I had been intending to blog about a confluence of stories about stories for a few weeks.

First, I was sitting in on lectures by untenured and adjunct faculty this semester, doing year-end evaluations. In the middle of one lecture, it occurred to me: The story matters. A good lecture is a cross product of story and facts (or data, or knowledge).

What if a lecture is only good as a story? It is like empty calories from sugar. We feel good for a while, but pretty soon we feel an emptiness. Nothing of value remains.

What if a lecture is only good for its facts? I see this often, and probably do this all too often. Good slides, but no story to make the audience care. The result is no interest. We may gain something, but we don't enjoy it much. And Schneier tells us that we might not even gain that much -- without a story that makes the information available to us, we may well forget it.

Soon after that, I ran across Ira Glass: Tips on storytelling at Presentation Zen. Glass says that the basic building blocks of a good story are the anecdote itself, which raises an implicit question, and moments of reflection. which let the user soak in the meaning.

Soon after that, I was at Iowa State's HCI forum and saw a research poster on the role of narrative in games and other virtual realities. It referred to the Narrative Paradigm of Walter Fisher (unexpected Iowa connection!), which holds that "All meaningful communication is a form of storytelling." And: "People experience and comprehend their lives as a series of ongoing narratives." (emphasis added)

Then, a couple of weeks later, I read the Schneier paper. So maybe I was predisposed to make connections to stories.

Our audiences -- software developers, students, business people -- are all engaged in their own ongoing narratives. How do we connect what we are teaching with one of their narratives? When we communicate Big Ideas, we might even strive to create a new thread for them, a new ongoing narrative that will define parts of their lives. I know that OOP, functional programming, and agile techniques do that for developers and students. The stories we tell help them move in that direction.

Some faculty seem to make connections, or create new threads. Some "just" lecture. Others do something more interactive. These are the faculty whom students want to take for class.

Others don't seem to make the connections. The good news for them -- for me -- is that one can learn how to tell stories better. The first step is simply to be aware that I am telling a story, and so to seek the hook that will make an idea memorable, worthwhile, and valuable. A lot of the motivation lies with the audience, but I have to hold up my end of the bargain.

Not just any story will do. People want a story that helps them do something. I usually know when my story isn't hitting the mark; if not before telling it, then after. The remedy usually lies in one of two directions: finding a story that is about my audience and not (just) me, or making my story real by living it first. Real problems and real solutions mean more than an concocted stories about abstract ideas of what might be.


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

May 14, 2007 7:25 PM

Persuasion, Teaching, and New Practice

I have written three posts recently [ 1 | 2 | 3 ] on various applications of Bruce Schneier's The Psychology of Security to software development and student learning. Here's another quote:

The moral here is that people will be persuaded more by a vivid, personal story than they will by bland statistics and facts, possibly solely due to the fact that they remember vivid arguments better.

I think that this is something that many of us know intuitively from experience both as learners and as teachers. But the psychological evidence that Schneier cites give us all the more reason to think carefully about many of the things we do. Consider how it applies to...

... "selling" agile ideas, to encouraging adoption among the developers who make software. The business people who make decisions about the making of software. The students who learn how to make software from us.

... "marketing" CS as a rewarding, worthwhile, challenging major and career path.

... "framing" ideas and practices for students whom we hope to help grow in some discipline.

Each of these audiences responds to vivid examples, but the examples that persuade best will be stories that speak to the particular desires and fears of each. Telling personal stories -- stories from our own personal experiences -- seem especially persuasive, because they seem more real to the listener. The listener probably hasn't had the experience we relate, but real stories have a depth to them that often can't be faked.

I think my best blogging fits this bill.

As noted in one of the earlier entries, prospect theory tells us that "People make very different trades-offs if something is presented as a gain than if something is presented as a loss." I think this suggests that we must frame arguments carefully and explicitly if we hope to maximize our effect. How can we frame stories most beneficially for student learning? Or to maximize the chance that developers adopt, or clients accept, new agile practices?

I put the words "selling", "marketing", and "framing" in scare quotes above for a reason. These are words that often cause academics great pause, or even lead academics to dismiss an idea as intellectually dishonest. But that attitude seems counter to what we know about how the human brain works. We can use this knowledge positively -- use our newfound powers for good -- or negatively -- for evil. It is our choice.

Schneier began his research with the hope of using what he learned for good, to help humans understand their own behavior better and so to overcome their default behavior. But he soon learned that this isn't all that likely; our risk-intuitive behaviors are automatic, too deeply-ingrained. Instead he hopes to pursue a middle road -- bringing our feelings of security into congruence with the reality of security. (For example, he now admits that palliatives -- measures that make users feel better without actually improving their security -- may be acceptable, if they result in closer congruence between feeling and reality.)

This all reminded me of Kathy Sierra's entry What Marketers Could Do For Teachers. There, she spoke the academically incorrect notion that teachers could learn from marketers because they:

  • "know what turns the brain on"
  • "know how to motivate someone almost instantly"
  • "know how to get--and keep--attention"
  • "spend piles of money on improving retention and recall"
  • "know how to manipulate someone's thoughts and feelings about a topic"

"Manipulate someone's thoughts and feelings about a topic." Sounds evil, or at least laden with evil potential. Sierra acknowledges the concern right up front...

[Yes, I'm aware how horrifying this notion sound -- that we take teachers and make them as evil as marketers? Take a breath. You know that's not what I'm advocating, so keep reading.]

Kathy meant just what Schneier is trying to do, that we can learn not the motivations of marketing but their understanding of the human mind, the human behavior that makes possible the practices of marketing. Our motivations are already good enough.


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

May 11, 2007 9:29 AM

Fish is Fish

Yesterday's post on the time value of study reminded me a bit of Aesop's fable The Ant and the Grasshopper. So perhaps you'll not be surprised to read a post here about a children's book.

cover image of Fish is Fish

While at workshop a couple of weeks ago, I had the pleasure of visiting my Duke friends and colleagues Robert Duvall and Owen Astrachan. In Owen's office was a copy of the book Fish Is Fish, by well-known children's book author Leo Lionni. Owen and Robert recommended the simple message of this picture book, and you know me, so... When I got back to town, I checked it out.

The book's web site summarizes the book as:

A tadpole and a minnow are underwater friends, but the tadpole grows legs and explores the world beyond the pond and then returns to tell his fish friend about the new creatures he sees. The fish imagines these creatures as bird-fish and people-fish and cow-fish and is eager to join them.

The story probably reaches young children in many ways, but the first impression it left on me was, "You can't imagine what you can't experience." Then I realized that this was both an overstatement of the story and probably wrong, so I now phrase my impression as, "How we imagine the the rest of the world is strongly limited by who we are and the world in which we live." And this theme matters to grown-ups as much as children.

Consider the programmer who knows C or Java really well, but only those languages. He is then asked to learn functional programming in, say, Scheme. His instructor describes higher-order procedures and currying, accumulator passing and tail-recursion elimination, continuations and call/cc. The programmer sees all these ideas in his mind's eye as C or Java constructs, strange beasts with legs and fins.

Or consider the developer steeped in the virtues and practices of traditional software engineering. She is then asked to "go agile", to use test-first development and refactoring browsers, pair programming and continuous integration, the planning game and YAGNI. The developer is aghast, seeing these practices in her mind's eye from the perspective of traditional software development, horrific beasts with index cards and lack of discipline.

When we encounter ideas that are really new to us, they seem so... foreign. We imagine them in our own jargon, our own programming language, our own development style. They look funny, and feel unnecessary or clunky or uncomfortable or wrong.

But they're just different.

Unlike the little fish in Lionni's story, we can climb out of the water that is our world and on to the beach of a new world. We can step outside of our experiences with C or procedural programming or traditional software engineering and learn to live in a different world. Smalltalk. Scheme. Ruby. Or Erlang, which seems to have a lot of buzz these days. If we are willing to do the work necessary to learn something new, we don't flounder in a foreign land; we make our universe bigger.

Computing fish don't have to be (just) fish.

----

(Ten years ago, I would have used OOP and Java as the strange new world. OO is mainstream now, but -- so sadly -- I'm not sure that real OO isn't still a strange new world to most developers.)


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

May 10, 2007 4:04 PM

Internalization as Investment

Maybe I am making too much of this and this. Reader Chris Turner wrote to comment that not internalizing is natural:

The things that I internalize are things I personally use. ... "Use" != "Have to know for a quiz". The reason I internalize them is because it's faster to remember than to look it up. If I hardly ever use it, though, the time spent learning it is wasted time. YAGNI as applied to knowledge, I suppose. ... [E]specially in the software development field, that this is not only acceptable, but encouraged. I simply don't have enough time to learn all I can about every design pattern out there. I have, however, internalized several that have been useful to me in particular.

I agree that one will -- and needs to -- internalize only what one uses on a regular basis. So as an instructor I need to be sure to give students opportunities to use the ideas that I hope for them to internalize. However, I am often disappointed that, even in the face of these opportunities, students seem to choose other activities (or no programming activities at all) and thus miss the chance to internalize an important idea. I guess I'm relying on the notion that students can trust that the ideas I choose for them are worth learning. People who bothered to master a theoretical construct like call/cc were able to create the idea of a continuation-based web server, rather than having to wait to be a third-generation adopter of a technology created, pre-processed, and commoditized by others.

But there's more. As one of my colleagues said yesterday, part of becoming educated is learning how to internalize, through conscious work. Perhaps we need to do a better job helping students to understand that this is one of the goals we have for them.

This leads me to think about another human bias documented in Schneier's article psychology article. I think that student behavior is also predicted by time discounting, the practice of valuing a unit of resource today more than the same unit of resource at a future date. In the financial world, this makes great sense, because a dollar today can be invested and earn interest, thus becoming more than $1 at the future date. The choice we face in valuing future resources is in predicting the interest rate.

I think that many of us, especially when we are first learning to learn, underestimate the "interest rate", the rate of return on time spent studying and learning-by-programming. Investment in a course early in the semester, especially when learning a new language or programming style, is worth much more than an equivalent amount of time spent later preparing for assignments and exams. And just as in the financial world, investing more time later often cannot make up for the ground lost to the early, patient investor. A particularly self-aware student once told me that he had used what seemed to be the easy first few weeks of my Programming Languages course to dive deep into Scheme and functional programming on his own. Later, when the course material got tougher, he was ready. Other students weren't so lucky, as they were still getting comfortable with syntax and idiom when they had to confront new content such as lexical addressing.

I like the prospect of thinking about the choice between internalizing and relying on external cues in terms innate biases on risk and uncertainty. This seems to give me a concrete way to state and respond to the issue -- to make changes in how I present my classes that can help students by recognizing their subconscious tendencies.


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

May 08, 2007 7:54 PM

Risk in Delivering Software

You ever notice
how anyone driving slower than you is an idiot,
and anyone driving faster than you is a maniac?

-- George Carlin

I spent my time flying back from Montreal reading Bruce Schneier's popular article The Psychology of Security and had a wonderful time. Schneier is doing want any good technologist should do: try to understand how the humans who use their systems tick. The paper made me harken back to my days studying AI and reasoning under uncertainty. One of the things we learned then is that humans are not very good at reasoning in the face of uncertainty. and most don't realize just how bad they are. Schneier studies the psychology of risk and probabilistic reasoning with the intention of understanding how and why humans so often misjudge values and trade-offs in his realm of system security. As a software guy, my thoughts turned in different directions. The result will be a series of posts.

To lead off, Schneier describes a couple of different models for how humans deal with risk. Here's the standard story he uses to ground his explanation:

Here's an experiment .... Subjects were divided into two groups. One group was given the choice of these two alternatives:
  • Alternative A: A sure gain of $500.
  • Alternative B: A 50% chance of gaining $1,000.

The other group was given the choice of:

  • Alternative C: A sure loss of $500.
  • Alternative D: A 50% chance of losing $1,000.

The expected values of A and B are the same, likewise C and D. So we might expect people in the first group to choose A 50% of the time and B 50% of the time, likewise C and D. But some people prefer "sure things", while others prefer to gamble. According to traditional utility theory from economics, we would expect people to choose A and C (the sure things) at roughly the same rate, and B and D (the gambles) at roughly the same rate. But they don't...

But experimental results contradict this. When faced with a gain, most people (84%) chose Alternative A (the sure gain) of $500 over Alternative B (the risky gain). But when faced with a loss, most people (70%) chose Alternative D (the risky loss) over Alternative C (the sure loss).

This gave rise to something called prospect theory, which "recognizes that people have subjective values for gains and losses". People have evolved to prefer sure gains to potential gains, and potential losses to sure losses. If you live in a world where survival is questionable and resources are scarce, this makes a lot of sense. But it also leads to interesting inconsistencies that depend on our initial outlook. Consider:

In this experiment, subjects were asked to imagine a disease outbreak that is expected to kill 600 people, and then to choose between two alternative treatment programs. Then, the subjects were divided into two groups. One group was asked to choose between these two programs for the 600 people:
  • Program A: "200 people will be saved."
  • Program B: "There is a one-third probability that 600 people will be saved, and a two-thirds probability that no people will be saved."

The second group of subjects were asked to choose between these two programs:

  • Program C: "400 people will die."
  • Program D: "There is a one-third probability that nobody will die, and a two-thirds probability that 600 people will die."

As before, the expected values of A and B are the same, likewise C and D. But in this experiment A==C and B==D -- they are just worded differently. Yet human bias toward sure gains to and potential losses holds true, and we reach an incongruous result: People overwhelmingly prefer Program A and Program D in their respective choices!

While Schneier looks at how these biases apply to the trade-offs we make in the world of security, I immediately began thinking of software development, and especially the so-called agile methods.

First let's think about gains. If we think not in terms of dollars but in terms of story points, we are in a scenario where gain -- an additive improvement to our situation -- is operative. It would seem that people out to prefer small, frequent releases of software to longer-term horizons. "In our plan, we can guarantee delivery of 5 story points each week, determined weekly as we go along, or we can offer an offer a 60% chance of delivering an average of 5 story points a week over the next 12 months." Of course, "guaranteeing" a certain number of points a week isn't the right thing to do, but we can drive our percentage up much closer to 100% the shorter the release cycle, and that begins to look like a guarantee. Phrased properly, I think managers and developers ought to be predisposed by their psychology to prefer smaller cycles. That is the good bet, evolutionarily, in the software world; we all know what vaporware is.

What about losses? For some reason, my mind turned to refactoring here. Now, most agile developers know that refactoring is a net gain, but it is phrased in terms of risk and loss (of immediate development time). Phrased as "Refactor now, or maybe pay the price later," this choice falls prey to human bias preference for potential losses over sure losses. No wonder selling refactoring in these terms is difficult! People are willing to risk carrying design debt, even if they have misjudged the probability of paying a big future cost. Maybe design debt and the prospect of future cost is the wrong metaphor for helping people see the value of refactoring.

But there is one more problem: optimism bias. It turns out that people tend to believe that they will outperform other people engaged in the same activity, and we tend to believe that more good will happen to us than bad. Why pay off design debt now? I'll manage the future trajectory of the system well enough to overcome the potential loss. We tend to underestimate both the magnitude of coming loss and the probability of incurring a loss at all. I see this in myself, in many of my students, and in many professional developers. We all think we can deliver n LOC this week even though other teams can deliver only n/2 LOC a week -- and maybe even if we delivered n/2 LOC last week. Ri-i-i-i-ight.

There is a lot of cool stuff in Schneier's paper. It offers a great tutorial on the fundamentals of human behavior and biases when reacting to and reasoning about risk and probability. It is well worth a read for how these findings apply in other areas. I plan a few more posts looking at applications in software development and CS education.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

April 23, 2007 3:44 PM

Discipline and Experience

I don't have time to keep up with the XP mailing list these days, especially when it spins off into a deep conversation on a single topic. But while browsing quickly last week before doing an rm on my mailbox, I ran across a couple of posts that deserved some thought.

Discipline in Practice

In a thread that began life as "!PP == Hacking?", discussion turned to how much discipline various XP practices demand, especially pair programming and writing tests (first). Along the way, Ron Jeffries volunteered that he is not always able to maintain discipline without exception: "I am the least disciplined person you know ..."

Robert Biddle followed:

I was pleased to read this. I'm always puzzled when people talk about discipline as a good thing in itself. I would consider it a positive attribute of a process that it required less, rather than more, discipline.

One of the things I've learned over the years is that, while habit is a powerful mechanism, processes that require people to pay close attention to details and to do everything just so are almost always destined to fail for the majority of us. It doesn't matter if the process is a diet, a fitness regimen, or a software methodology. People eventually stop doing them. They may say that they are still following the process, but they aren't, and that may be worse than just stopping. Folks often start the new discipline with great energy, psyched to turn over a new leaf. But unless they can adapt their thinking and lifestyle, they eventually tire of having to follow the rules and backslide. Alistair Cockburn has written a good agile software book that starts with the premise that any process must build on the way that human minds really work.

Later in the thread, Robert notes that -- contrary to what many folks who haven't tried XP for very long think -- XP tolerates a lower level of discipline than other methodologies:

For example, as a developer, I like talking to the customer lots; and as a customer I like talking to developers. That takes way less discipline for me than working with complex specs.

My general point is that it makes sense for processes and tools to work with human behaviour, supporting and protecting us where we are weak, and empowering us where we are strong.

He also points out that the boundary between high discipline and low discipline probably varies from person to person. A methodology (or diet, or training regimen) capable of succeeding within a varied population must hit close to the population's typical threshold and be flexible enough that folks who lie away from that threshold have a chance find a personal fit.

As methodology, XP requires us to change how we think, but it places remarkably few picayune demands on our behavior. A supportive culture can go a long toward helping well-intended newbies give it a fair shake. And I don't think it is as fragile in its demands as the Atkins Diet or many detailed running plans for beginners.

Accelerating Experience

In a different thread, folks were discussing how much experience one needs in order to evaluate a new methodology fairly, which turned to the bigger question of how much project experience one can realistically obtain. Projects that last 6 months or 2 years place something of an upper bound on our experience. I like Laurent Bossavit's response:

> It takes a lot of time to get experienced.
> How many software development projects can you
> experience in a life-time? How many can you
> experience with three years of work experience?

Quite a lot, provided they're small enough.

Short cycles let you make mistakes faster, more often. They let us succeed faster. They let us learn faster.

A post later in this thread by someone else pointed out that P and other agile approaches change the definition of a software project. Rather than thinking in terms of a big many-month or multi-year project, we think in terms of 2- or 3-week releases. These releases embody a full cycle from requirements through delivery, which means that we might think of each release as a "whole" project. We can do short retrospectives, we can adapt our practices, we can shift direction in response to feedback.

Connections... This reminds me of an old post from Laurent's blog that I cited in an old post of my own. If you want to increase your success rate, double your failure rate; if you want to double your failure rate, all you have to do is halve your project length. Ideas keep swirling around.


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

April 21, 2007 4:54 PM

Making Something Tangible

It occurred to me recently one thing that makes administrative work different from my previous kinds of work, something that accounts for an occasional dissatisfaction that I never used to feel as a matter of course.

In my administrative role, I can often work long and hard without producing anything.

It's not that I don't do anything as department head. It's just that the work doesn't always result in a product, something tangible, something complete that one can look to and say, "I made that." Much of a head's work is about relationships, interaction, and one-one interaction. These are all valuable outcomes, and they may result in something tangible down the road. Meeting with students, parents of prospective students, industry partners, or prospective donors all may result in something tangible -- eventually. And the payoff -- say, from a donor -- can be quite tangible, quite sizable! But in the meantime, I sometimes feel like, "What did I accomplish today?"

This realization struck me a week or so back when I finished producing the inaugural issue of my department's new newsletter. I wrote nearly all of the content, arranged the rest, and did all of the image preparation and document layout. When I got done, I felt that sense one gets from making something.

I get that feeling when I write software. I think that one of the big wins from small, frequent releases is the shot of adrenaline that it gives the developers. We rarely talk about this advantage, instead speaking of the value of the releases in terms of customer feedback and quality. But the buzz that we developers feel in producing a whole something, even if it's a small whole, probably contributes more than we realize to motivation and enjoyment. That's good for the developers, and for the customer, too.

I get that feeling when I write code and a lesson for teaching a class, too. The face-to-face delivery creates its own buzz.

This makes me wonder how students feel about frequent release dates, or small, frequent homework assignments. I often use this approach in my courses, but again more for "customer-side" and quality reasons. Maybe students feel good producing something, making tangible progress, every week or so? Or does the competing stress of several other courses, work, and life create an overload? Even if students prefer this style, it does create a new force to be addressed: small frequent failures must be horribly disheartening. I need to be sure that students feel challenge and success.

Sheepishly, I must admit that I've never asked my students how they feel about this. I will next week. If you want to share your thoughts, please do.


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

April 19, 2007 4:05 PM

Walking Out The Door

Today I am reminded to put a variant of this pattern into practice:

The old-fashioned idea (my door is always open; when you want to talk, c'mon in) was supposed to give people down the line access to you and your ears. The idea was that folks from layers below you would come and clue you in on what was really happening.

I don't think that ever worked for most of us. Most folks didn't have the courage to come in, so we only learned what was on the minds of the plucky few. We were in our environment, not theirs. We couldn't verify what we were hearing by looking, touching, and listening in the first person. And we got fat from all that sitting.

I ran into this quote in Jason Yip's post Instead of opening the door, walk through it. Jason is seconding an important idea: that an open door policy isn't enough, because it leaves the burden for engaging in communication on others -- and there are reasons that these other folks may not engage, or want to.

This idea applies in the working-world relationship between supervisors and their employees, but it also applies to the relationship between a service provider and its customers. This includes software developers and their customers. If we as software developers sit in a lab, even with our door open, our customer may never come in to tell us what they need. They may be afraid to bother us; they may not know what they need. Agile approaches seek to reduce the communication gap between developers and customers, sometimes to the point of putting them together in a big room. And these approaches encourage developers to engage the customer in frequent communication in a variety of ways, from working together on requirements and acceptance to releasing working software for customer use as often as possible.

As someone who is sitting in a classroom with another professor and a group of grad students just now, I can tell you that this idea applies to teachers and students. Two years ago tomorrow, I wrote about my open office hours -- they usually leave me lonely like the Maytag Repairman. Learning works best when the instructor engages the student -- in the classroom and in the hallway, in the student union, on the sidewalk, and at the ballgame. Often, students yearn to be engaged, and learning is waiting to happen. It may not happen today, in small talk about the game, but at some later time. But that later time may well depend on the relationship built up by lots of small talk before. And sometimes the learning happens right there on the sidewalk, when the students feel able to ask their data structures question out among the trees!

But above, I said that today reminded me of a variant of this pattern... Beginning Monday and culminating today, I was fortunate to have a member of my department engage me in conversation, to question a decision I had made. Hurray! The open door (and open e-mail box) worked. We have had a very good discussion by e-mail today, reaching a resolution. But I cannot leave our resolution sitting in my mail archive. I have to get up off my seat, walk through the door, and ensure that the discussion has left my colleague satisfied, in good standing with me. I'm almost certain it has, as I have a long history with this person as well as a lot of history doing e-mail.

But I have two reasons to walk through the door and engage now. First, my experience with e-mail tells me that sometimes I am wrong, and it is almost always worth confirming conclusions face-to-face. If I were "just" faculty, I might be willing to wait until my next encounter with this colleague to do the face-to-face. My second reason is that I am department head these days. This places a burden on communication, due to the real and perceived differences in power that permeate my relationships with colleagues. The power differential means that I have to take extra care to ensure that interactions, whether face to face or by e-mail, are building our relationship and not eroding it. Still being relatively new to this management business, it still feels odd that I have to be careful in this way. These folks are my colleagues, my friends! But as I came to realize pretty quickly, moving into the Big Office Downstairs changes things, whatever we may hope. The best way to inoculate ourselves from the bad effects of the new distance? Opening the door and walking through it.

Oh, and this applies to the relationship between teachers and students, too. I understand that as an advisor to my grad students, having been a grad student whose advisor encouraged healthy and direct communication. But I see it in my relationship with undergraduates, too, even in the classroom. A little care tending one-on-one and one-on-many relationships goes a long way.

(And looking back at that old post about the Friends connection, I sometimes wonder if any of my colleagues has a good Boss Man Wallingford impression yet. More likely, one of my students does!)


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

April 17, 2007 7:46 AM

Less May Be More

Over at Lambda the Ultimate, I ran into a minimal Lisp system named PicoLisp. Actually, I ran into a paper that describes PicoLisp as a "radical approach to application development", and from this paper I found my way to the software system itself.

PicoLisp is radical in eschewing conventional wisdom about programming languages and application environments. The Common Lisp community has accepted much of this conventional wisdom, it would seem, in reaction to criticism of some of Lisp's original tenets: the need for a compiler to achieve acceptable speed, static typing within an abundant set of specific types, and the rejection of pervasive, shallow dynamic binding. PicoLisp rejects these ideas, and takes Lisp's most hallowed feature, the program as s-expression, to its extreme: a tree of executable nodes, each of which...

... is typically written in optimized C or assembly, so the task of the interpreter is simply to pass control from one node to the other. Because many of those built-in Lisp functions are very powerful and do a lot of processing, most of the time is spent in the nodes. The tree itself functions as a kind of glue.

In this way an "interpreter" that walks the tree can produce rather efficient behavior, at least relative to what many people think an interpreter can do.

As a developer, the thing I notice most in writing PicoLisp code is its paucity of built-in data types. It supports but three, numbers, symbols, and lists. No floats; no strings or vectors. This simplifies the interpreter in several ways, as it now need to make run-time checks on fewer different types. The price is paid by the programmer in two ways. First, at programming time, the developer must create the higher-order data types as ADTs -- but just once. This is a price that any user of a small language must pay and was one of the main trade-offs that Guy Steele discussed in his well-known OOPSLA talk Growing a Language. Second, at run time, the program will use more space and time than if the those types were primitive in the compiler. But space is nearly free these days, and the run-time disadvantage turns out to be smaller than one might imagine. The authors of PicoLisp point out that the freedom their system gives them saves them a much more expensive sort of time -- developer time in an iterative process that they liken to XP.

Can this approach work at all in the modern world? PicoLisp's creators say yes. They have implemented in PicoLisp a full application development environment that provides a database engine, a GUI, and the generation of Java applets. Do they have the sort of competitive advantage that Paul Graham's writes about having had at the dawn of ViaWeb? Maybe so.

As a fan of languages and language processors, I always enjoy reading about how someone can be productive working in an environment that stands against conventional wisdom. Less may be more, but not just because it is less (say, fewer types and no compiler). It is usually more because it is also different (s-expressions as powerful nodes glued together with simple control).


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

April 12, 2007 6:54 PM

Agile Moments: Accountability and Continuous Feedback in Higher Ed

It's all talk until the tests run.
-- Ward Cunningham

A couple of years ago, I wrote about what I call my Agile Moments, and soon after wrote about another. If I were teaching an agile software development course, or some other course with an agile development bent, I'd probably have more such posts. (I teach a compiler development course this fall...) But I had an Agile Moment yesterday afternoon in an un-software-like place: a talk on program assessment at universities.

Student outcomes assessment is one of those trendy educational movements that comes and go like the seasons or the weather. Most faculty in the trenches view it with unrelenting cynicism, because they've been there before. Some legislative body or accrediting agency or university administrator decides that assessment is essential, and they deem it Our Highest Priority. The result is an unfunded mandate on departments and faculty to create an assessment plan and implement the plan. The content and structure of the plans are defined from above, and these are almost always onerous -- they look good from above but they look like unhelpful busy work to professors and students who just want to do computer science, or history, or accounting.

But as a software developer, and especially as someone with an agile bent, I see the idea of outcomes assessment as a no-brainer. It's all about continuous feedback and accountability.

Let's start with accountability. We don't set out to write software without a specification or a set of stories that tell us what our goal is. Why do we think we should start to teach a course -- or a four-year computer science degree program! -- without having a spec in hand? Without some public document that details what we are trying to achieve, we probably won't know if we are delivering value. And even if we know, we will probably have a hard time convincing anyone else.

The trouble is, most university educators think that they know what an education looks like, and they expect the rest of the world to trust them. For most of the history of universities, that's how things worked. Within the university, faculty shared a common vision of what to do when, and outside the students and the funders trusted them. The relationship worked out fine on both ends, and everyone was mostly happy.

Someone at the talk commented that the call for student and program outcomes assessment "break the social contract" between a university and its "users". I disagree and think that the call merely recognizes that the social contract is already broken. For whatever reason, students and parents and state governments now want the university to demonstrate its accountable.

While this may be unsettling, it really shouldn't surprise us. In the software world, most anyone would find it strange if the developers were not held accountable to deliver a particular product. (That is even more true in the rest of the economy, and this difference is the source of much consternation among folks outside the software world -- or the university.) One of the things I love about what Kent Beck has been teaching for the last few years is the notion of accountability, and the sort of honest communication that aims at working fairly with the people who hire us to build software. I don't expect less of my university.

In the agile software world, we often think about to whom they are accountable, and even focus on the best word to use, to send the right message: client, customer, user, stakeholder, .... Who is my client when I teach a CS course? My customer? My stakeholders? These are complex question, with many answers depending on the type of school and the level at which we ask them. Certainly students, parents, the companies who hire our graduates, the local community, the state government, and the citizens of the state are all partial stakeholders and thus potential answers as client or customer.

Outcomes assessment forces an academic department to specify what it intends to deliver, in a way that communicate the end product more effectively to others. This offers better accountability. It also opens the door to feedback and improvement.

When most people talk about outcomes assessment, they are thinking of the feedback component. As an agile software developer, I know that continuous feedback is essential to keeping me on track and to helping me improve as a developer. Yet we teach courses at universities and offer degrees to graduates while collecting little or no data as we go along. This is the data that we might use to improve our course or our degree programs.

The speaker yesterday quoted someone as saying that universities "systematically deprive themselves" of input from their customers. We sometimes collect data, but usually at the end of the semester, when we ask students to evaluate the course and the instructor using a form that often doesn't tell us what we need to know. Besides, the end of the semester is too late to improve the course while teaching the students giving the feedback!

From whom should I as instructor collect data? How do I use that data to improve a course? How do I use that data to improve my teaching more generally? To whom must I provide an accounting of my performance?

We should do assessment because we want to know something -- because we want to learn how to do our jobs better. External mandates to do outcomes assessment demotivate, not motivate. Does this sound anything like the world of software development?

Ultimately, outcomes assessment comes down to assessing student learning. We need to know whether students are learning what we want them to learn. This is one of those issues that goes back to the old social contract and common understanding of the university's goal. Many faculty define what they want students to know simply as "what our program expects of them" and whether they have learned it as "have they passed our courses?" But such circular definitions offer no room for accountability and no systematic way for departments t get better at what they do.

The part of assessment everyone seems to understand is grading, the assessment of students. Grades are offered by many professors as the primary indicator that we are meeting our curricular goals: students who pass my course have learned the requisite content. Yet even in this area most of us do an insufficient job. What does an A in a course mean? Or an 87%? When a student moves on to the next course in the program with a 72% (a C in most of my courses) in the prerequisite course, does that mean the student knows 72% of the material 100% of the way, 100% of the material 72% of the way, some mixture of the two, or something altogether different? And do we want to such a student writing the software on which we will depend tomorrow?

Grades are of little use to students except perhaps as carrots and sticks. What students really need is feedback that helps them improve. They need feedback that places the content and process they are learning into the context of doing something. More and more I am convinced that we need to think about how to use the idea of course competencies that West and Rostal implemented in their apprenticeship-based CS curriculum as a way to define for students and instructors alike what success in a course or curriculum mean.

My mind made what it thinks is one last connection to agile software development. One author suggests that we think of "assessment as narrative", as a way of telling our story. Collecting the right data at the right times can help us to improve. But it can also help us tell our story better. I think a bit part of agile development is telling our story: to other developers on the team, to new people we hire, to our clients and customers and stakeholders, and to our potential future clients and customers. The continuous feedback and integration that we do -- both on our software and on our teams -- is an essential cog in defining and telling that story. But maybe my mind was simply in overdrive when it made this connection.

It was the at end of this talk that I read the quote which led me to think of Kurt Vonnegut, coincidental to his passing yesterday, and which led me to write this entry. So it goes.


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

April 10, 2007 7:54 PM

Incendiary Humor Considered Harmful?

For a good laugh, take a look at Jeff Overbey's "considered harmful" considered harmful web page. He writes:

I'm not entirely sure why, but I searched ACM and IEEE for all papers with "Considered Harmful" in the title. The length of this list should substantiate my claim that that phrase should be banned from the literature.

And he lists them all. The diversity of areas in computing where people have off Dijkstra's famous screed on go-to statements is pretty broad. The papers range from computer graphics (Bishop et al.) to software engineering (de Champeaux), from the use of comments (Beckman) to web services (Khare et al.) and human-centered design (Donald Norman!). Guy Steele has two entries on the list, one from his classic lambda series of papers and the other on arithmetic shifting, of all things.

A lot of the "considered harmful" papers deal with low-level programming constructs, like go-to, =, if-then-else, and the like. People doing deep and abstract work in computing and software development can still have deeply-held opinions about the lowest-level issues in programming -- and hold them so strongly that feel obligated to make their case publicly.

There is even a paper on the list that uses the device in a circular reference: "'Cloning Considered Harmful' Considered Harmful", by Kapser and Godfrey. This idea is taken to its natural endpoint by Eric Meyer in his probably-should-be-a-classic essay "Considered Harmful" Essays Considered Harmful. While Meyer deserves credit for the accuracy his title, I can't help but thinking he'd have score more style points from the judges for the pithier "Considered Harmful" Considered Harmful.

Of course, that would invite the obvious rejoinder "'Considered Harmful' Considered Harmful" Considered Harmful, and where would that leave us?

Meyer's essay makes a reasonable point:

It is not uncommon, in the context of academic debates over computer science and Web standards topics, to see the publication of one or more "considered harmful" essays. These essays have existed in some form for more than three decades now, and it has become obvious that their time has passed. Because "considered harmful" essays are, by their nature, so incendiary, they are counter-productive both in terms of encouraging open and intelligent debate, and in gathering support for the view they promote. In other words, "considered harmful" essays cause more harm than they do good.

I think that many authors adopt the naming device as an attempt to use humor to take the sharp edge off what is intended as an incendiary argument, or at least a direct challenge to what is perceived as an orthodoxy that no one thinks to challenge any more.

Apparently, the CS education community is more prone than most to making this sort of challenge. CS educators are indeed almost religious in their zeal for particular approaches, and the conservatism of academic CS is deeply entrenched. Looking at Overbey's list, I identify at least nine "considered harmful" papers on CS education topics, especially on the teaching of intro CS courses:

  • Westfall, "'Hello, World' Considered Harmful"
  • Rosenberg and Koelling, "I/O Considered Harmful..."
  • Martin, "Toy Projects Considered Harmful"
  • Johnson, "C in the First Course Considered Harmful"
  • Schneider, "Compiler Textbook Bibliographies Considered Harmful"
  • Hitchner et al., "Programming Early Considered Harmful"
  • Buck and Stucki, "Design Early Considered Harmful"
  • Kay, "Bandwagons Considered Harmful..." (in curriculum development)
  • Hu, "Dataless Objects Considered Harmful"
I've read far too many of these... And there may well be other intro CS papers on the list that I don't recognize just from their names.

Some of the papers on the CS ed list are even in direct opposition to one another! Consider "Programming Early Considered Harmful" and "Design Early Considered Harmful". If we can't do programming early, and we can't do design early, what can we do? Certainly not structured programming; that's on the bigger list twice.

This tells you something about the differences that arise in CS education, as well as the community's sense of humor. It may also say something about our level of creativity! (Just joking... I know some of these folks and know them to be quite creative.)


Posted by Eugene Wallingford | Permalink | Categories: General, Software Development

April 05, 2007 8:57 PM

Feats of Association

An idea is a feat of association.
-- Robert Frost

Yesterday I went to a talk by Roy Behrens, an earlier talk of whose I enjoyed very much and blogged about. That time he talked about teaching as a "subversive inactivity", and this time he spoke more on the topic of his scholarly interest, in creativity and design, ideas and metaphors, similarities and differences, even camouflage! Given that these are his scholarly interests, I wasn't surprised that this talk touched on some of the same concepts as his teaching talk. There are natural connection between how ideas are formed at the nexus os similarity and difference and how one can best help people to learn. I found this talk energizing and challenging in a different sort of way.

In the preceding paragraph, I first wrote that Roy "spoke directly on the topic of his scholarly interest", but there was little direct about this talk. Instead, Roy gave us parallel streams of written passages and images from a variety of sources. This talk felt much like an issue of his commonplace book/journal Ballast Quarterly Review, which I have blogged about before. The effect was mesmerizing, and it had its intended effect in illustrating his point: that the human mind is a connection-making machine, an almost unwilling creator of ideas that grow out of the stimuli it encounters. We all left the talk with new ideas forming.

I don't have a coherent, focused essay on this talk yet, but I do have a collection of thoughts that are in various stages of forming. I'll share what I have now, as much for my own benefit as for what value that may have to you.

Similarity and difference, the keys to metaphor, matter in the creation of software. James Coplien has written an important book that explicates the roles of commonality analysis and variability analysis in the design of software that can separate domain concerns into appropriate modules and evolve gracefully as domain requirements change. Commonality and variability; similarity and difference. As one of Roy's texts pointed out, the ability to recognize similarity and difference is common to all practical arts -- and to scientists, creators, and inventors.

The idea of metaphor in software isn't entirely metaphorical. See this paper by Noble, Biddle, and Tempero that considers how metaphor and metonymy relate to object-oriented design patterns. These creative fellows have explored the application of several ideas from the creative arts to computing, including deconstruction and postmodernism.

To close, Roy showed us the 1952 short film Blacktop: A Story of the Washing of a School Play Yard. And that's the story it told, "with beautiful slow camera strides, the washing of a blacktop with water and soap as it moves across the asphalt's painted lines". This film is an example of how to make something fabulous out of... nothing. I think the more usual term he used was "making the familiar strange". Earlier in his talk he had read the last sentence of this passage from Maslow (emphasis added):

For instance, one woman, uneducated, poor, a full-time housewife and mother, did none of these conventionally creative things and yet was a marvelous cook, mother, wife, and home-maker. With little money, her home was somehow always beautiful. She was a perfect hostess. Her meals were banquets, her taste in linens, silver, glass crockery and furniture was impeccable. She was in all these areas original, novel, ingenious, unexpected, inventive. I learned from her and others like her that a first-rate soup is more creative than a second-rate painting, and that, generally, (un)cooking or parenthood or making a home could be creative while poetry need not be; it cold be uncreative.

Humble acts and humble materials can give birth to unimagined creativity. This is something of a theme for me in the design patterns world, where I tell people that even novices engage in creative design when they write the simplest of programs and where so-called elementary patterns are just as likely to give rise to creative programs as Factory or Decorator.

Behrens's talk touched on two other themes that run through my daily thoughts about software, design, and teaching. One dealt with tool-making, and the other with craft and limitations.

At one point during the Q-n-A after the talk, he reminisced about Let's Pretend, a radio show from his youth which told stories. The value to him as a young listener lay in forcing -- no, allowing -- him to create the world of the story in his own mind. Most of us these days are conditioned to approach an entertainment venue looking for something that has already been assembled for us, for the express purpose of entertaining ourselves. Creativity is lost when our minds never have the opportunity to create, and when our minds' ability to create atrophies from disuse. One of Roy's goals in teaching graphic design students is to help students see that they have the tools they need to create, to entertain.

This is true for artists, but in a very important sense it is true for computer science students, too. We can create. We can build our own tools--our own compilers, our own IDEs, our own applications, our own languages... anything we need! That is one of the great powers of learning computer science. We are in a new and powerful way masters of our own universe. That's one of the reasons I so enjoy teaching Programming Languages and compilers: because they confront CS students directly with the notion that their tools are programs just like any other. You never have to settle for less.

Finally, may favorite passage from Roy's talk plays right into my weakness for the relationship between writing and programming, and for the indispensable role of limitation in creativity and in learning how to create. From Anthony Burgess:

Art begins with craft, and there is no art until craft has been mastered. You can't create until you're willing to subordinate the creative impulses to the constriction of a form. But the learning of craft takes a long time, and we all think we're entitled to shortcuts.... Art is rare and sacred and hard work, and there ought to be a wall of fire around it.

One of my favorite of my blog posts is from March 2005, when I wrote a piece called Patterns as a Source of Freedom. Only in looking back now do I realize that I quoted Burgess there, too -- but only the sentence about willing subordination! I'm glad that Roy gave the context around that sentence yesterday, because it takes the quote beyond constriction of form to the notion of art growing out of craft. It then closes with that soaring allusion. Anyone who has felt even the slightest sense of creating something knows what Burgess means. We computer scientists may not like to admit that what we do is sometimes art, and that said art is rare and sacred, but that doesn't change reality.

Good talk -- worth much more in associations and ideas than the lunch hour it cost. My university is lucky to have Roy Behrens, and other thinkers like him, on our faculty.


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

March 22, 2007 6:53 PM

Patterns in Space and Sound -- Merce Cunningham

A couple of nights I was able to see a performance by the Merce Cunningham Dance Company here on campus. This was my first exposure to Cunningham, who is known for his exploration of patterns in space and sound. My knowledge of the dance world is limited, but I would call this "abstract dance". My wife, who has some background in dance, might call it something else, but not "classical"!

The company performed two pieces for us. The first was called eyeSpace, and it seemed the more avant garde of the two. The second, called Split Sides, exemplifies Cunningham's experimental mindset quite well. From the company's web site:

Split Sides is a work for the full company of fourteen dancers. Each design element was made in two parts, by one or two artists, or, in the case of the music, by two bands. The order in which each element is presented is determined by chance procedure at the time of the performance. Mathematically, there are thirty-two different possible versions of Split Sides.

And a mathematical chance it was. At intermission, the performing arts center's director came out on stage with five people, most local dancers, and a stand on which to roll a die. Each of the five assistants in turn rolled the die, to select the order of the five design elements in question: the pieces, the music, the costumes, the backgrounds, and a fifth element that I've forgotten. This ritual heightened the suspense for the audience, even though most of us probably had never seen Split Sides before, and must have added a little spice for the dancers, who do this piece on tour over and over.

In the end, I preferred the second dance and the second piece of music (by Radiohead), but I don't know to what extent this enjoyment derived from one of the elements or the two together. Overall, I enjoyed the whole show quite a bit.

Not being educated in dance, my take on this sort of performance is often different from the take of someone who is. In practice, I find that I enjoy abstract dance even more than classical. Perhaps this comes down to me being a computer scientist, an abstract thinker who enjoys getting lost in the patterns I see and hear on stage. A lot of fun comes in watching the symmetries being broken as the dance progresses and new patterns emerge.

Folks trained in music may sometimes feel differently, if only because the patterns we see in abstract dance are not the patterns they might expect to see!

Seeing the Merce company perform reminded of a quote about musician Philip Glass, which I ran across in the newspaper while in Carefree for ChiliPLoP:

... repetition makes the music difficult to play.

"As a musician, you look at a Philip Glass score and it looks like absolutely nothing," says Mark Dix, violist with the Phoenix Symphony, who has played Glass music, including his Third String Quartet.

"It looks like it requires no technique, nothing demanding. However, in rehearsal, we immediately discovered the difficulty of playing something so repetitive over so long a time. There is a lot of room for error, just in counting. It's very easy to get lost, so your concentration level has to be very high to perform his music."

When we work in the common patterns of our discipline -- whether in dance, music, or software -- we free our attention to focus on the rest of the details of our task. When we work outside those patterns, we are forced to attend to details that we have likely forgotten even existed. That may make us uncomfortable, enough so that we return to the structure of the pattern language we know. That's not necessarily a bad thing, for it allows us to be productive in our work.

But there can be good in the discomfort of the broken pattern. One certainly learns to appreciate the patterns when they are gone. The experience can remind us why they are useful, and worth whatever effort they may require. The experience can also help us to see the boundaries of their usefulness, and maybe consider a combination, or see a new pattern.

Another possible benefit working without the usual patterns is hidden in Dix's comments above. Without the patterns, we have to concentrate. This provides a mechanism whereby we attend to details and hone our concentration, our attention to detail. I think it also allows us to focus on a new technique. Programming at the extremes, without an if-statement, say, forces you to exercise the other techniques you know. The result may be that you are a better user of polymorphism even after you return to the familiar patterns that include imperative selection.

And I can still enjoy abstract dance and music as an outsider.

There is another, more direct connection between Cunningham's appearance and software. He has worked with developers to create a new kind of choreography software called DanceForms 1.0. While his troupe was in town, they asked the university to try to arrange visits with computer science classes to discuss their work. We had originally planned for them to visit our User Interface Design course and our CS I course (which has a media computation theme), but schedule changes on our end prevented that. I had looked forward to hearing Cunningham discuss what makes his product special, and to see how they had created "palettes of dance movement" that could be composed into dances. That sounds like a language, even if it doesn't have any curly braces.


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

March 21, 2007 4:35 PM

END DO

John Backus

What prompted me to finally write about Frances Allen winning the Turing Award was a bit of sad news. One of the pioneers of computing, John Backus, has died. Like Allen, Backus also worked in the area of programming languages. He is most famous as the creator of Fortran, as reported in the Times piece:

Fortran changed the terms of communication between humans and computers, moving up a level to a language that was more comprehensible by humans. So Fortran, in computing vernacular, is considered the first successful higher-level language."

I most often think of Backus's contribution in terms of the compiler for Fortran. His motivation to write the compiler and design the language was that shared by many computer scientists through history: laziness. Here is my favorite quote from the CNN piece:

"Much of my work has come from being lazy," Backus told Think, the IBM employee magazine, in 1979. "I didn't like writing programs, and so, when I was working on the IBM 701 (an early computer), writing programs for computing missile trajectories, I started work on a programming system to make it easier to write programs."

Work on a programming system to make it easier to write programs... This is the beginning of computer science as we know it!

Backus's work laid the foundation for Fran Allen's work; in fact, her last big project was called PTRAN, an homage to Fortran that stands for Parallel TRANslation.

One of my favorite Backus papers is his Turing Award essay, Can Programming Be Liberated from the von Neumann Style? (subtitled: A Functional Style and its Algebra of Programs). After all his years working on language for programmers and translators for machines, he had reached a conclusion that the mainstream computing world is still catching up to, that a functional programming style may serve us best. Every computer scientist should read it.

This isn't the first time I've written of the passing of a Turing Award winner. A couple of years ago, I commented on Kenneth Iverson, also closely associated with his own programming language, APL. Ironically, APL offers a most extreme form of liberation from the von Neumann machine. Thinking of Iverson and Backus together at this time seems especially fitting.

The Fortran programmers among us know what the title means. RIP.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

March 15, 2007 4:55 PM

Writing about Doing

Elvis Costello

Last week I ran across this quote by noted rocker Elvis Costello:

Writing about music is like dancing about architecture -- it's really a stupid thing to want to do.

My immediate reaction was an intense no. I'm not a dancer, so my reaction was almost exclusively to the idea of writing about music or, by extension, other creative activities. Writing is the residue of thinking, an outward manifestation of the mind exploring the world. It is also, we hope, occasionally a sign of the mind growing, and those who read can share in the growth.

I don't imagine that dancing is at all like writing in this respect.

Perhaps Costello meant specifically writing about music and other pure arts. But I did study architecture for a while, and so I know that architecture is not a pure art. It blends the artistic and purely creative with an unrelenting practical element: human livability. People have to be able to use the spaces that architects create. This duality means that there are two levels at which one can comment on architecture, the artistic and the functional. Costello might not think much of people writing about the former, but he may allow for the value in people writing about the latter.

I may be overthinking this short quote, but I think it might have made more sense for Costello to have made this analogy: "Writing about music is like designing a house about dancing ...". But that doesn't have any of the zip of his original!

I can think of one way in which Costello's original makes some sense. Perhaps it is taken out of context, and implicit in the context is the notion of only writing about music. When someone is only a critic of an art form, and not a doer of the art form, there is a real danger of becoming disconnected from what practitioners think, feel, and do. When the critic is disconnected from the reality of the domain, the writing loses some or all of its value. I still think it is possible for an especially able mind to write about without doing, but that is a rare mind indeed.

What does all this have to do with a blog about software and teaching? I find great value in many people's writing about software and about teaching. I've learned a lot about how to build more expressive, more concise, and more powerful software from people who have shared their experiences writing such software. The whole software patterns movement is founded upon the idea that we should share our experiences of what works, when and why. The pedagogical patterns community and the SIGCSE community do the same for teachers. Patterns really do have to be founded in experience, so "only" writing patterns without practicing the craft turns out to be a hollow exercise for both the reader and the writer, but writing about the craft is an essential way for us to share knowledge. I think we can share knowledge both of the practical, functional parts of software and teaching and of the artistic element -- what it is to make software that people want to read and reuse, to make courses that people want to take. In these arts, beauty affects functionality in a way that we often forget.

I don't yet have an appetite for dancing about software, but my mind is open on the subject.


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

March 13, 2007 1:55 PM

Yannis's Law on Programmer Productivity

I'm communications chair for OOPSLA 2007 and was this morning updating the CFP for the research papers track, adding URLs to each member of the program committee. Chair David Bacon has assembled quite a diverse committee, in terms of affiliation, continent, gender, and research background. While verifying the URLs by hand, I visited Yannis Smaragdakis's home page and ran across his self-proclaimed Yannis's Law. This law complements Moore's Law in the world of software:

Programmer productivity doubles every 6 years.

I have long been skeptical of claims that there is a "software crisis", that as hardware advances give us incredibly more computing power our ability to create software grows slowly, or even stagnates. When I look at the tools that programmers have today, and at what students graduate college knowing, I can't take seriously the notion that programmers today are less productive than those who worked twenty or more years ago.

We have made steady advances in the tools available to mainstream programmers over the last thirty years, from frameworks and libraries, to patterns, to integrated environments such as .NET and Eclipse, down to the languages we use, like Perl, Ruby, and Python. All help us to produce more and better code in less time than we could manage even back when I graduated college in the mid-1980s.

Certainly, we produced far fewer CS graduates and and employed far fewer programmers thirty years ago, and so we should not be surprised that that cohort was -- on average -- perhaps stronger than the group we produce today. But we have widened the channel of students who study CS in recent decades, and these kids do all right in industry. When you take this democratization of the pool of programmers into account, I think we have done all right in terms of increasing productivity of programmers.

I agree with Smaragdakis's claim that a decent programmer working with standard tools of the day should be able to produce Parnas's KWIC index system in a couple of hours. I suspect that a decent undergrad could do so as well.

Building large software systems is clearly a difficult task, one usually dominated by human issues and communication issues. But we do our industry a disservice when we fail to see how far we have come.


Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

March 09, 2007 9:11 PM

SIGCSE Day 2: Read'n', Writ'n', 'Rithmetic ... and Cod'n'

Grady Booch, free radical

Back in 2005, Grady Booch gave a masterful invited talk to close OOPSLA 2005, on his project to preserve software architectures. Since then, he has undergone open-heart surgery to repair a congenital defect, and it was good to see him back in hale condition. He's still working on his software architecture project, but he came to SIGCSE to speak to us as CS educators. If you read Grady's blog, you'll know that he blogged about speaking to us back on March 5. (Does his blog have permalinks to sessions that I am missing?) There, he said:

My next event is SIGCSE in Kentucky, where I'll be giving a keynote titled Read'n, Writ'n, 'Rithmetic...and Code'n. The gap between the technological haves and have-nots is growing and the gap between academia and the industries that create these software-intensive systems continues to be much lamented. The ACM has pioneered recommendations for curricula, and while there is much to praise about these recommendations, that academia/industry gap remains. I'll be offering some observations from industry why that is so (and what might be done about it).

And that's what he did.

A whole generation of kids has grown up not knowing a time without the Internet. Between the net, the web, iPods, cell phones, video games with AI characters... they think they know computing. But there is so much more!

Grady recently spent some time working with grade-school students on computing. He did a lot of the usual things, such as robots, but he also took a step that "walked the walk" from his OOPSLA talk -- he showed his students the code for Quake. Their eyes got big. There is real depth to this video game thing!

Grady is a voracious reader, "especially in spaces outside our discipline". He is a deep believer in broadening the mind by reading. This advice doesn't end with classic literature and seminal scientific works; it extends to the importance of reading code. Software is everywhere. Why shouldn't read it to learn to understand our discipline? Our CS students will spend far more of their lives reading code than writing it, so why don't we ask them to read it? It is a great way to learn from the masters.

According to a back of the envelope calculation by Grady and Richard Gabriel 38 billion lines of new and modified code are created each year. Code is everywhere.

While there may be part of computer science that is science, that is not what Booch sees on a daily basis. In industry, computing is an engineering problem, the resolution of forces in constructing an artifact. Some of the forces are static, but most are dynamic.

What sort of curriculum might we develop to assist with this industrial engineering problem? Booch referred to the IEEE Computer Society's Software Engineering Body of Knowledge (SWEBOK) project in light of his own software architecture effort. He termed SWEBOK "noble but failed", because the software engineering community was unable to reach a consensus on the essential topics -- even on the glossary of terms! If we cannot identify the essential knowledge, we cannot create a curriculum to help our students learn it.

He then moved on to curriculum design. As a classical guy, he turned to the historical record, the ACM 1968 curriculum recommendations. Where were we then?

Very different from now. A primary emphasis in the '68 curriculum was on mathematical and physical scientific computing -- applications. We hadn't laid much of the foundation of computer science at that time, and the limitations of both the theoretical foundations and physical hardware shaped the needs of the discipline and thus the curriculum. Today, Grady asserts that the real problems of our discipline are more about people than physical limits. Hardware is cheap. Every programmer can buy all the computing power she needs. The programmer's time, on the other hand, is still quite expensive.

What about ACM 2005? As an outsider, Grady says, good work! He likes the way the problem has been decomposed into categories, and the systematic way it covers the space. But he also asks about the reality of university curricula; are we really teaching this material in this way?

But he sees room for improvement and so offered some constructive suggestions for different ways to look at the problem. For example, the topical categories seem limited. The real world of computing is much more diverse than our curriculum. Consider...

Grady has worked with SkyTV. Most of their software, built in web-centric world, is less than 90 days old. Their software is disposable! Most of their people are young, perhaps averaging 28 years old or so.

He has also worked with people at the London Underground. Their software is old, and their programmers are old (er, older). They face a legacy problem like no other, both in their software and in their physical systems. I'm am reminded of my interactions with colleagues from Lucent, who work with massive, old physical switching systems driven by massive, old programs that no one person can understand.

What common theme do SkyTV and London Underground folks share? Building software is a team sport.

Finally, Grady looked at the ACM K-12 curriculum guidelines. He was so glad to see it, so glad to that see we are teaching the ubiquitous presence of computing in contemporary life to our young! But we are showing them only the fringes of the discipline -- the applications and the details of the OS du jour. Where do we teach them our deep ideas, the beauty and nobility of our discipline?

As he shifted into the home stretch of the talk, Grady pointed us all to a blog posting he'd come across called The Missing Curriculum for Programmers and High Tech Workers, written by a relatively recent Canadian CS grad working in software. He liked this developers list and highlighted for us many of the points that caught his fancy as potential modifications to our curricula, such as:

  • Sometimes, worker harder or longer won't get the job done.
  • Learn a scripting language!
  • Documentation is essential, but it must be tied to code.
  • Learn the patterns of organization behavior.
  • Learn about many other distinctly human elements of the profession, like meetings (how to stay awake, how to avoid them), hygiene (friend or foe?), and planning for the future.

One last suggestion for our consideration involved his Handbook of Software Architecture. There, he has created categories of architectures that he considers the genres of our discipline. Are these genres that our students should know about? Here is a challenging thought experiment: what if these genres were the categories of our curriculum guidelines? I think this is a fascinating idea, even if it ultimately failed. How would a CS curriculum change if it were organized exclusively around the types of systems we build, rather than mostly on the abstractions of our discipline? Perhaps that would misrepresent CS as science, but what would it mean for those programs that are really about software development, the sort of engineering that dominates industry?

Grady said that he learned a few lessons from his excursion into the land of computing curriculum about what (else) we need to teach. Nearly all of his lessons are the sort of things non-educators seem always to say to us: Teach "essential skills" like abstraction and teamwork, and teach "metaskills" like the ability to learn. I don't diminish these remarks as not valuable, but I don't think these folks realize that we do actually try to teach these, but they are hard to learn, especially in the typical school setting, and so hard to teach. We can address the need to teach a scripting language by, well, adding a scripting language to the curriculum in place of something less relevant these days. But newbies in industry don't abstract well because they haven't gotten it yet, not because we aren't trying.

The one metaskill on his list that we really shouldn't forget, but sometimes do, is "passion, beauty, joy, and awe". This is what I love about Grady -- he considers these metaskills, not squishy non-technical effluvium. I do, too.

During his talk, Grady frequently used the phrase "right and noble" to describe the efforts he sees folks in our industry making, including in CS education. You might think that this would grow tiresome, but it didn't. It was uplifting.

It is both a privilege and a responsibility, says Grady, to be a software developer. It is a privilege because we are able to change the world in so many, so pervasive, so fundamental ways. It is a responsibility for exactly the same reason. We should keep this mind, and be sure that our students know this, too.

At the end of his talk, he made one final plug that I must relay. He says that patterns are the coolest, most important thing that have happened in the software world over the last decade. You should be teaching them. (I do!)

And I can't help passing on one last comment of my own. Just as he did at OOPSLA 2005, before giving his talk he passed by my table and said hello. When he saw my iBook, he said almost exactly the same thing he said back then: "Hey, another Apple guy! Cool."


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

February 23, 2007 7:58 PM

**p++^=q++=*r---s

I thought about calling this piece "The Case Against C" but figured that this legal expression in the language makes a reasonably good case on its own. Besides, that is the name of a old paper by P.J. Moylan from which I grabbed the expression. ( PDF | HTML, minus footers with quotes) When I first ran across a reference to this paper, I thought it might make a good post for my attempt at the Week of Science, but by the author's own admission this is more diatribe than science.

C is a medium-level language combining
the power of assembly language with
the readability of assembly language.

I finally finished reading the paper on my way home from ChiliPLoP, and it presented a well-reasoned argument that computer scientists and programmers consider using languages that incorporate advances in programming languages since the creation of C. He doesn't diss C, and even professes an admiration for it; rather he speaks to specific features about which we know much more now than we did in the early 1970s. I ended up collecting a few good quotes, like the one above, and a few good facts, trivia, and guidelines. I'll share some of the more notable with you.

Facts, Trivia, and Guidelines

  • One of the features of C that is behind the times is its weak support for modular code. C supports separate compilation of modules, but Moylan reminds us that modularity is really about information hiding and abstraction. In this regard, C's system is lacking. Moylan gives a very nice description of ten practices that one can adopt in order to build effective modular programs in C, ranging from technical advice such as "Exactly one header file per module.", "Every module must import its own header file, as a consistency check.", and "The compiler warning 'function call without prototype" should be enabled, and any warning should be treated as an error." to team practices such as "Ideally, programmers working in a team should not have access to one another's source files. They should share only object modules and header files." He is not optimistic about the consistent use of these rules, though:

    Now, the obvious difficulty with these rules is that few people will stick to them, because the compiler does not enforce them. ... And, what is worse, it takes only one programmer in a team to break the modularity of a project, and to force the rest of the team to waste time with grep and with mysterious errors caused by unexpected side-effects.

  • Moylan gives a simple example that as concisely as possible how C's #include directive can lead to a program that is in an inconsistent state because some modules which should have been re-compiled were not. The remedy of always recompiling everything is obviously unattractive to anyone working on a large system.

  • Conventional wisdom says that C compilers produce faster code than compilers for other things. Moylan objects on several grounds, including the lack of any substantial recent evidence for the conventional wisdom. He closes with my favorite piece of trivia from the paper:

    It is true that C compilers produced better code, in many cases, than the Fortran compilers of the early 1970s. This was because of the very close relationship between the C language and PDP-11 assembly language. (Constructs like *p++ in C have the same justification as the three-way IF of Fortran II: they exploit a special feature of the instruction set architecture of one particular processor.) If your processor is not a PDP-11, this advantage is lost.

    I learned my assembly language and JCL on an IBM mainframe and so never had the pleasure of writing assembly for a PDP-11. (I did learn Lisp on a PDP-8, though...) Now I want to go learn about the PDP-11's assembly language so that I can use this example at greater depth in my compilers course next semester.

    Favorite Quotes

    You've already seen one above. My other favorite is:

    Much of the power of C comes from having a powerful preprocessor. The preprocessor is called a programmer.

    There were other good ones, but they lack the technical cleanness of the best because they could well be said of other languages. Examples from this category include "By analysis of usenet source, the hardest part of C to use is the comment." and "Real programmers can write C in any language." (My younger readers may not know what Moylan means by "usenet", which makes me feel old. But they can learn more about it here.)

    ----

    As readers here probably know from earlier posts such as this one, I'm as tempted by a guilty language pleasure as anyone, so I enjoyed Moylan's article. But even if we discount the paper's value for its unabashed advocacy on language matters, we can also learn from his motivation:

    I am not so naive as to expect that diatribes such as this will cause the language to die out. Loyalty to a language is very largely an emotional issue which is not subject to rational debate. I would hope, however, that I can convince at least some people to re-think their positions.

    I recognise, too, that factors other than the inherent quality of a language can be important. Compiler availability is one such factor. Re-use of existing software is another; it can dictate the continued use of a language even when it is clearly not the best choice on other grounds. (Indeed, I continue to use the language myself for some projects, mainly for this reason.) What we need to guard against, however, is making inappropriate choices through simple inertia.

    Just to keep in mind that we have a choice of language each time we start a new project is a worthwhile lesson to learn.


  • Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

    February 21, 2007 5:50 PM

    ChiliPLoP 2007 Redux

    Our working group had its most productive ChiliPLoP in recent memory this year. The work we did isn't ready for public consumption yet, so I can't post a link just yet, but I am hopeful that we will be able to share our results with interested educators soon enough. For now, a summary.

    This year, we made substantial progress toward producing a well-documented resource for instructors who want to teach Java and OOP. As our working paper begins:

    The following set of exercises builds up a simple application over a number of iterations. The purpose is to demonstrate, in a small program, most of the key features of object-oriented programming in Java within a period of two to three weeks. The course can then delve more deeply into each of the topics introduced, in whatever order the instructor deems appropriate.

    An instructor can use this example to lay a thin but complete foundation in object-oriented Java for an intro course within the first few weeks of the semester. By introducing many different ideas in a simple way early, the later elements of the course can be ordered at the instructor's discretion. So many other approaches to teaching CS 1 create strict dependencies between topics and language constructs, which limits the instructor's approach over the course of the whole semester. The result is that most instructors won't adopt a new approach, because they either cannot or do not want to be tied down for the whole semester. We hope that our example enables instructors to do OO early while freeing them to build the rest of their course in a way that fits their style, their strengths and interests, and their institution's curriculum.

    Our longer-term goal is that this resource serve as a good example for ourselves and for others who would like to document teaching modules and share them with others. By reducing external dependencies to a minimum, such modules should assist instructors in assembling courses that use good exercises, code, and OO programming practice.

    ... but where are the patterns? Isn't a PLoP conference about patterns? Yes, indeed, and that is one reason that I'm more excited about the work we did this week than I have been in a while. By starting with a very simple little exercise, growing progressively into an interesting simulation via short, simple steps, we have assembled both a paradigmatic OO CS 1 program and the sequence of changes necessary to grow it. To me, this is an essential step in identifying the pattern language that generates the program. I may be a bit premature, but I feel as if we are very close to having documented a pattern sequence in the Alexandrian sense. Such a pattern sequence is an essential part of a pattern-oriented approach to design, and one that only a few people -- Neil Harrison and Jim Coplien -- have written much about. And, like Alexander's idea of pattern diagnosis, pattern sequences will, I think, play a valuable role in how we teach pattern-directed design. My self-assigned task is to explore this extension of our ChiliPLoP work while the group works on filling in some details and completing our public presentation.

    One interesting socio-technical experiment we ran this week was to write collaboratively using a Google doc. I'm still not much a fan of browser-based apps, especially word processors, but this worked out reasonably well for us. It was fast, performed autosaves in small increments, and did a great job handling the few edit conflicts we caused in two-plus days. We'll probably continue to work in this doc for a few more weeks, before we consider migrating the document to a web page that we can edit and style directly.

    Two weeks from today, the whole crew of us will be off to SIGCSE 2007, which is an unusual opportunity for us to follow up our ChiliPLoP and hold ourselves accountable for not losing momentum. Of course, two weeks back home like this would certainly wipe my mind clear of any personal momentum I have built up, so I will need to be on guard!


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

    February 05, 2007 8:46 PM

    Programming Patterns and "The Conciseness Conjecture"

    For most of my research career, I have been studying patterns in software. In the beginning didn't think of it in these terms. I was a graduate student in AI doing work in knowledge-based systems, and our lab worked on so-called generic tasks, little molecules of task-specific design that composed into systems with expert behavior. My first uses of the term "pattern" were home-grown, motivated by an interest to help novice programmers recognize and implement the basic structures that made up their Pascal, Basic, and C programs. In the mid-1990s I came into contact with the work of Christopher Alexander and the software patterns community, and I began to write up patterns of both sorts, including Sponsor-Selector, loops, Structured Matcher, and even elementary patterns of Scheme programming for recursion. My interest turned to the patterns at the interface between different programming styles, such as object-oriented and functional programming. It seemed to me that many object-oriented design patterns implemented constructs that were available more immediately in functional languages, and I wondered whether it were true that patterns in any one style would reflect the linguistic shortcomings of the style, implementing ideas available directly in another style.

    My work in this area has always been more phenomenological than mathematical, despite occasional short side excursions into promising mathematics like group and category theory. I recall a 6- to 9-month period five or six years ago when a graduate student and I looked group theory and symmetries as a possible theoretical foundation for characterizing relationships among patterns. I think that this work still holds promise, but I have not had a chance to take it any further.

    Only recently did I finally read Matthias Felleisen's 1991 paper On the Expressive Power of Programming Languages. I should have read it sooner! This paper develops a framework for comparing languages on the basis of their expressiveness powers and then applies it to many of the issues relevant to language research of the day. One section in particular speaks to my interest in programming patterns and shows how Felleisen's framework can help us to discern the relative merits of more expressive languages and the patterns that they embody. This section is called "The Conciseness Conjecture". Here is the conjecture itself:

    Programs in more expressive programming languages that use the additional features in a sensible manner contain fewer programming patterns than equivalent programs in less expressive languages.

    Felleisen gives a couple of examples to illustrate his conjecture, including one in which Scheme with assignment statements realizes the implementation of an stateful object more concisely, more clearly, and with less convention than a purely functional subset of Scheme. This is just the sort of example that led me to wonder whether functional programming's patterns, like OOP's patterns, embodied ideas that were directly expressible in another style's languages -- a Scheme extended with a simple object-oriented facility would make implementation of Felleisen's transaction manager even clearer than the stateful lambda expression that switches on transaction types.

    Stated as starkly as it is, I am not certain I believe the conjecture. Well, that's not quite true, because in one sense it is obviously true. A more expressive language allows us to write more concise code, and less code almost always means fewer patterns. This is true, of course, because the patterns reside in the code. I say "almost always" because there is an alternative to fewer patterns in smaller code: the same number of patterns, or more, in denser code!

    If we qualify "fewer programming patterns" as "fewer lower-level programming patterns", then I most certainly believe Felleisen's conjecture. I think that this paper makes important contribution to the study of software patterns by giving us a vocabulary and mechanism for talking about languages in terms of the trade-off between expressiveness and patterns. I doubt that Felleisen intended this, because his section on the Conciseness Conjecture confirms his uneasiness with pattern-driven programming. "The most disturbing consequence," he writes, of programming patterns is that they are an obstacle to understanding of programs for both human readers and program-processing programs." For him, an important result of his paper is to formalize "how the use of expressive languages seems to be the ability to abstract from programming patterns with simple statements and to state the purpose of a program in the concisest possible manner."

    This brings me back to the notions of "concise" and "dense". I appreciate the goal of using the most abstract language possible to write programs, in order to state as unambiguously and with as little text as possible the purpose and behavior of a program. I love to show my students how, after learning the basics of recursive programming. they can implement a higher-order operation such as fold to eliminate the explicit recursion from their programs entirely. What power! all because they are using a language expressive enough to allow higher-order procedure. Once you understand the abstraction of folding, you can write much more concise code.

    Where is the down side? Increasing concision ultimately leads to a trade-off on understandability. Felleisen points to the danger that dispersion poses for code readers: in the worst case, it requires a global understanding of the program to understand how the program embodies a pattern. But at the other end of the spectrum is the danger posed by concision: density. In the worst, the code is so dense as to overwhelm the reader's sense. If density were an unadulterated good, we would all be programming in a descendant of APL! The density of abstraction is often the reason "practical" programmers cite for not embracing functional programming is the density of the abstractions one finds in the code. It is an arrogance for us to imply that those who do not embrace Scheme and Haskell are simply not bright enough to be programmers. Our first responsibility is to develop means for teaching programmers these skills better, a challenge that Felleisen and his Teach Scheme! brigade have accepted with great energy. The second is to consider the trade-off between concision and dispersion in a program's understandability.

    Until we reach the purest sense of declarative programming, all programs will have patterns. These patterns are the recurring structures that programmers build within their chosen style and language to implement behaviors not directly supported by the language. The patterns literature describes what to build, in a given set of circumstances, along with some idea of how to build the what in a way that makes the most of the circumstances.

    I will be studying "On the Expressive Power of Programming Languages" again in the next few months. I think it has a lot more to teach me.


    Posted by Eugene Wallingford | Permalink | Categories: Computing, Patterns, Software Development

    February 02, 2007 6:13 PM

    Recursing into the Weekend

    Between meetings today, I was able to sneak in some reading. A number of science bloggers have begun to write a series of "basic concepts" entries, and one of the math bloggers wrote a piece on the basics of recursion and induction. This is, of course, a topic well on my mind this semester as I teach functional programming in my Programming Languages course. Indeed, I just gave my first lecture on data-driven recursion in class last Thursday, after having given an introduction to induction on Tuesday. I don't spend a lot of time on the mathematical sort of recursion in this course because it's not all that relevant to to the processing of computer programs. (Besides, it's not nearly as fun!)

    This would would probably make a great "basic concepts in CS" post sometime, but I don't have time to write it today. But if you are interested, you can browse my lecture notes from the first day of recursive programming techniques in class.

    (And, yes, Schemers among you, I know that my placement of parentheses in some of my procedures is non-standard. I do that in this first session or so so that students can see the if-expression that mimics our data type stand out. I promise not to warp their Scheme style with this convention much longer.)


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

    January 23, 2007 8:09 AM

    Class Personality and New Ideas

    People you've got the power over what we do
    You can sit there and wait
    Or you can pull us through
    Come along, sing the song
    You know you can't go wrong

    -- Jackson Browne, "The Load-Out"

    Every group of students is unique. This is evident every time I teach a course. I think I notice these differences most when I teach a course Programming Languages, the course I'm teaching this semester.

    In this course, our students learn to program in a functional style, using Scheme, and then use their new skills to build small language interpreters that help them to understand the principles of programming languages. Because we ask students to learn a new programming style and a language very different from any they know when the enter the course, this course depends more than most on the class's willingness to change their minds. This willingness is really attribute of each of the individuals in the class, but groups tend to develop a personality that grows out of the individual personalities which make it up.

    The last time I taught this course, I had a group that was eager to try new ideas. These folks were game from Day 1 to try something like functional programming. Many of them had studied a language called Mumps in another course, which had shown them the power that can be had in a small language that does one or two things well. Many of them were Linux hackers who appreciated the power of Unix and its many little languages. Scheme immediately appealed to these students, and they dove right in. Not all of them ended up mastering the language or style, but all made a good faith effort. The result was an uplifting experience both for them and for me. Each class session seemed to have a positive energy that drove us all forward.

    But I recall a semester that went much differently. That class of students was very pragmatic, focused on immediate skills and professional goals. While that's not always my orientation (I love many ideas for their own sake, and look for ways to improve myself by studying them), I no longer fault students who feel this way. They usually have good reasons for having developed such a mindset. But that mindset usually doesn't make for a very interesting semester studying techniques for recursive programming, higher-order procedures, syntactic abstractions, and the like. Sure, these ideas show up -- increasingly often -- in the languages that they will use professionally, and we can make all sorts of connections between the ideas they learn and the skills they will need writing code in the future. It's just that without a playful orientation toward new ideas, a course that reaches beyond the here-and-now feels irrelevant enough to many students to be seem an unpleasant burden.

    That semester, almost every day was a chore for me. I could feel the energy drain from my body as I entered the room each Tuesday and Thursday and encountered students who were ready to leave before we started. Eventually we got through the course, and the students may even have learned some things that they have since found useful. But at the time the course was like a twice-weekly visit to the dentist to have a tooth pulled.

    In neither of these classes was there only the one kind of student. The personality of the class was an amalgam, driven by the more talkative members or by the natural leaders among the students. In one class, I would walk into the room and find a few of them discussing some cool new thing they had tried since the last time we met; in the other, they would be discussing the pain of the current assignment, or a topic from some other course they were enjoying. These attitudes pervaded the rest of the students and, at least to some extent, me. As the instructor, I do have some influence over the class's emotional state of mind. If I walk into the room with excitement and energy, my students will feel that. But the students can have the same effect. The result is a symbiotic process that requires a boost of energy from both sides every class period.

    We are now two weeks into the new semester, and I am trying to get a feel for my current class. The vocal element of the class has been skeptical, asking lots of "why?" questions about functional programming and Scheme alike. So far, it hasn't been the negative sort of skepticism that leads to a negative class, and some of the discussion so far has had the potential to provoke their curiosity. As we get deeper into the meat of the course, and students have a chance to write code and see its magic, we could harness their skepticism into a healthy desire to learn more.

    Over the years, I've learned how better to respond to the sort of questions students ask at the outset of the semester in this course. My goal is to lead the discussion in a way that is at the same time intellectually challenging and pragmatic. I learned long ago that appealing only to the students' innate desire to learn abstract ideas such as continuations doesn't work for the students in my courses. In most practical ways, the course is about what they need to learn, not about what I want blather on about. And as much as we academics like papers such as Why Functional Programming Matters -- and I do like this paper a lot! -- it is only persuasive to programmers who are open to being persuaded.

    But I've also found that pandering to students by telling them that the skills they are learning can have an immediate effect on their professional goals does not work in this sort of course. Students are smart enough to see that even if Paul Graham got rich writing ViaWeb in Lisp, most of them aren't going to be starting their own companies, and they are not likely to get a job where Scheme or functional programming will matter in any direct way. I could walk into class each day with a different example of a company that has done something "in the real world" with Scheme or Haskell, and at the end of the term most students would have perceived only thirty isolated and largely irrelevant examples.

    This sort of course requires balancing these two sets of forces. Students want practical ideas, ideas that can change how they do their work. But we sell students short when we act as if they want to learn only practical job skills. By and large they do want ideas, ideas that can change how they think. I'm better at balancing these forces with examples, stories, and subtle direction of classroom discussion than I was ten or fifteen years ago, but I don't pretend to be able to predict where we'll all end up.

    Today we begin a week studying Scheme procedures and some of the features that make functional programming different from what they are used to, such as first-class procedures, variable arity, higher-order procedures, and currying. These are ideas with the potential to capture the students' imagination -- or to make them think to themselves, "Huh?" I'm hopeful that we'll start to build a positive energy that pulls us forward into a semester of discovery. I don't imagine that they'll be just like my last class; I do hope that we can be a class which wants to come together a couple of times every week until May, exploring something new and wonderful.


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

    January 15, 2007 11:45 AM

    Getting Worse in Order to Get Better

    Tiger Woods drives a ball

    Tiger Woods recently won the PGA's Player of the Year for the eighth time in his ten-year professional career. Since 1990, no other player has won the award more than twice. He is widely considered the most dominant athlete in any sport in the world -- which is saying a lot when you consider the amazing runs that tennis's Roger Federer and cycling's Lance Armstrong have had during Tiger's own run.

    Woods is great, but he also stands out for something else: his remarkable efforts to get better. Now, most pros are continually working on the games, trying to improve their skills. Woods has taken this effort to a new level, by completely rebuilding his swing twice during his professional career. Sportswriter Leonard Shapiro describes Woods's most recent reconstruction, back in 2004 and early 2005. In 2004, a lot of commentators thought that Tiger had perhaps peaked, as other players on the Tour had been winning the majors and left him as just another competition. Tiger wasn't striking the ball as well, and his tee shots were errant. He seemed to have gotten worse. But suddenly in 2005, he returned to the top of the leaderboard with a vengeance and had one of the all-time great years in PGA history.

    You see, while Tiger was seemingly getting worse, he was actually getting better.

    A golf swing is complex mechanical act. There is very little margin of error between a great shot and a merely good shot. At the top level of golf, the standard deviation is even smaller. When Tiger decided that he had reached a plateau in his game with his current swing, he knew that he had to develop an entirely new swing. And while he was building that new swing, using it on every shot for nearly eighteen months, he performed worse than he had with the old swing. Only after all that repetition, feedback, and adjustment did he have the swing he needed to regain his peak. And his new peak was even higher than the old one.

    This progression from plateau to valley to new peak is not unique to Tiger or to golf swings. Any complex skill that depends on muscle memory requires the sort of repetition and feedback that usually results in degraded performance during the learning phase. The key to improvement in this phase is patience. Learning a new skill takes time, while we train our brains and bodies to execute their tasks in an accurate, repeatable way.

    Mental skills, even ones that we carry out with more conscious attention, have this feature. Sometimes, we can make only small incremental improvements from our current skill base, but an effort to learn something radically different can alter our skill base in a qualitative way -- and result in radical improvements in our performance.

    Many programmers know this. The last couple of years, a common new year meme among bloggers has been to learn a new language. Often the language is something very different from their daily tools of Java and XML and C. Haskell, Ruby, Scheme, and Smalltalk seem to show up on peoples' lists frequently precisely because they are so different. They offer the promise of a radical improvement in skill because to master them requires looking at problems and solutions in a radically different. You can't speak fluid Haskell or Scheme without coming to grips with a functional mindset. Even if list comprehensions, continuations, and tail recursion are not part of the programming language you use in your day job, understanding them can help you use that language in a new way. And who knows, those features may ultimately make their way into your day job's language -- either this one, or the next one.

    Martin Fowler writes about his own experience crossing the improvement ravine on the way to new mastery. He even quotes Gerald Weinberg, whom I've mentioned occasionally since I first began blogging. Martin points out a couple of key insights. One is that sometimes the new thing doesn't work, at least for you. Worse, there is a Halting Problem complicating matters: you can't be sure if the technique has failed for you or if you just need to stick with it a little longer. The best hope for circumventing this problem is to have a good teacher working with you, whether in a classroom or one one one. Tiger had his coach, Hank Haney, to help him assess the state of his swing and decide to keep going, even during the darkest days of 2004. Working with colleagues or a trusted friend can also serve this purpose.

    I think another key to this process is a sort of courage. It's hard to be patient while you're failing, or while you're struggling with a new idea. In this context, your teacher coach, or friend plays the important role of support system, encouraging you to stick with the process. As with almost anything, doing it over and over helps us to have the courage we need. Tiger's 2004 rebuild was the second such publicized episode of his career, and I'm guessing that having succeeded in the first helped him to remain steadfast during the second. One requires less courage as one feels less fear. But I think that I will always feel a real fear anytime I step way outside my expertise in an effort to get better. Maybe even a great one such as Tiger does, too. Courage will always play a role.

    This notion of getting worse for a while in order to get better is on my mind right now because I have just begun a new semester in which I will try to teach Scheme and functional programming to a bunch of students who probably feel pretty comfortable in their imperative programming skills with Java, C++, and Ada. I have to help them see that mastering such a different new language, and especially style of programming, will require that they feel awkward for a while. The tried-and-true syntax, operators, idioms, and patterns no longer seem to work. That is scary. But it's worth going through this scary phase, practicing "the real thing" as much as they can. With practice and time, they will soon learn the new syntax, master the new operators, appreciate the new idioms and develop some of their own, and finally discover the new patterns that will make them better programmers than they were before.

    My memory is always drawn back to two former students in particular who approached this in a Tiger-like fashion. They went home every night for three weeks or so and just tried to write good functional programs in Scheme. They read my examples and those from the textbook; they experimented with small modifications and then large ones, eventually trying to write whole programs. For a while this was painful, because their programs broke and my evaluation of their homework didn't result in the easy As to which they had become accustomed. But suddenly -- or so it seemed -- they got it. They were excellent functional programmers. The rest of their Programming Languages course went smoothly, as they could focus on the language concepts without having to worry about whether they could make Scheme work for them.

    If the greatest golfer in the world, the most dominant athlete of a generation, can take the time to get worse for a while in order to get better, I think we all can. But do we have the patience and courage to take the chance and stay the course? And do we have the teachers and coaches who can help us along the way?


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

    December 21, 2006 2:49 PM

    User Documentation and Instructional Design

    Yesterday while clearing out some of the paper that has built up in my office over the course of the semester, I was reading through the conference copy of several sets of OOPSLA tutorial notes. One that grabbed by interest was from a tutorial that we had to cancel for lack of registration, on how to write user guides and tutorial documents. OOPSLA caters to software developers, and we knew at the time we accepted this one that the audience might be slim. But as I thought about the notes I was sad that we didn't attract more of an audience for this tutorial. It would have been useful to a lot of folks.

    I was struck by the fact that writers of documentation for users face many of the same issues that teachers face. The first part of the tutorial dealt with users and learning: what they need to learn, and how they can learn it. The writer needs to remember that the user doesn't see the system in the same way as the developer, and may in fact be a different sort of person entirely. This echoes the recent "our students aren't like us" theme in several of my posts. The tutorial then proceeds to give concrete advice on the such topics as:

    • the differences between learning by reading and learning by doing
    • the cognitive burden shouldered by learners
    • the distinction between dedicates learners and midtask learners

    I think that I sometimes assume that my students will be dedicated learners, focused on the ideas that I am trying to convey, rather than midtask learners, focused on getting something done. But I suspect that many students do a lot of their learning just-in-time, while attempting a programming assignment or homework problem. Midtask learners approach the learning task differently than the dedicated learner. In particular, they tend to look for what they need right now and stop reading as soon as they find it -- or realize that they won't! This makes brevity and specificity important elements of user documentation. They are just as important when writing instructions and tutorials for students.

    The tutorial goes on to give concrete advice and examples on how to write instructions, how to induce rehearsal in the learner, and how to organize presentation to avoid overloading the learner. Almost every page of the notes has something to use as I think about refining my spring Programming Languages and Paradigms course. I've written extensive lecture notes for this course, of which I'm proud. But I think I'll use some of my prep time in the coming term to apply the ideas from this tutorial to my lectures. I can think of a couple ways to improve them:

    • varying the strategies I use to invoke rehearsal (zooming and out, changing modes of presentation, and supporting a new assertion with what we just learned)

    • making sure that my instructions clearly communicate their intention, endpoint, time frame, and possible signs o success and failure.

    I guess I am not surprised by the similarities among writing user doc and writing for students (and teaching from that writing), but it never occurred to me to mine the former to help me improve the latter.

    These tutorial notes were fun to read even without having the presenter in the room. They were written well, spare but engaging. That said, as with most printouts from slide presentations, I would have learned a lot more by having the writer tell the stories that were abstracted into her slides. And I definitely would like to see the examples that she had planned to distribute to illustrate the ideas in the tutorial.

    User documentation is certainly not the only other writing form from which instructors can draw ideas and inspiration. Nat Pryce recently wrote about the idea of using the comic book as a form for end-user documentation, and there may be something we instructors could learn from comic book writers. Before you scoff, recall that the U.S. 9/11 Commission Report The Path to 9/11 was adapted into a highly-acclaimed comic book. (If I recall correctly, either artist Ernie Colon or writer Sid Jacobson is from my adopted state of Iowa.)

    I think the OOPSLA crowd missed a good opportunity to learn from this tutorial. But there is one consolation... I believe that the tutorial presenter is currently writing a book on this topic. I'll definitely pick up a copy, and not because I plan to write a lot of user documentation.


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

    December 20, 2006 5:16 PM

    The Long Tail as Software Designer

    Almost every day I am reminded of how the way the world works is changing all around us. For example, Philip Windley writes of the day, coming soon, when MP3 player are like pens -- "everywhere, given away, easily abandoned, even disposable". (I almost wrote "ballpoint pens", but that would betray my ever more apparent state of being a dinosaur.)

    Then I learned about My Dream App, which lies at the convergence of American Idol, the web, and the independent software world:

    My Dream App is a grand experiment to see what happens when you combine the expertise of some of the best talents in the software and tech world with great ideas and feedback from everyone else.

    Like Idol, My Dream App had open tryouts to get into the pool of contestants and then judging by a panel of experts as the apps were winnowed through a series of rounds. However, My Dream App's panel of experts puts Idol's to shame! At the end, the viewing public selected winners by voting on-line. At stake was not a recording contract but a contract to have the idea implemented by a crack team of Mac developers, with royalties for life. The coding team has some great developers, including one of the guys behind SubEthaEdit.

    Simon (Cowell) says: thumbs down!

    Steve Wozniak

    While I'm not all that enamored by most of the apps that finished at the top of the pile, with perhaps one exception, I think that this is a great idea. It exploits the power of a large number of people to brainstorm ideas and then allows them to participate in a selection process that is guided by informed folks who can provide a more focused perspective. And the allure of having Woz act as Simon Cowell must surely have attracted a few people to take their shot at submitting an idea. "That's the most pathetic feature I've seen since Bill Atkinson wanted to prevent users from specifying their own desktop patterns on the original Mac."

    This is a new variation in the space of idea generation that I have written about before. On one end of a continuum is the great solo creator like Steve Jobs, who seems to have an innate sense of what of is good; at the other end is Howard Moskowitz, who produces an insanely large set of possibilities, including strange ones that we think no one might like, and then lets people discover what they like. My Dream App is more in the Moskowitz vein, but with a twist -- let everyone with an internet connection build your set of possibilities for you, and then let the crowd work with informed guides to winnow the set. The ubiquity of the web makes possible a collaborative process that would have been unwieldy at best in earlier times.

    I wonder long it will be before a mainstream producer -- say, an automobile manufacturer -- uses this sort of approach to design a mainstream product. Just imagine... the 2009 Long Tail coupe, original idea by a insurance executive in Hawarden, Iowa, refined by the masses under the watchful eye of Lee Iacocca. Many auto manufacturers do worse on their own. When harnessed in the right sort of process, the wisdom of the crowd is a powerful force.


    Posted by Eugene Wallingford | Permalink | Categories: General, Software Development

    December 02, 2006 10:42 AM

    Writing Code

    Here's the thing. I like to write code.

    I like to write code that most people take for granted. I like to write code to solve hard problems. I like to write simple programs. I like to solve the programming assignments that I set before my students. I like to discover problems to solve and then solve them with code. Sometimes, I like to make up problems just so I can write code to solve them.

    A colleague of mine is fond of reminding university professors that they are not like most of our students. He means that in the sense that we professors were usually good students, or at least students who liked school, and that we can't expect our students to think the way we do or to like school the way we did. This can be useful as we design our courses and plan our day-to-day interactions with students. It's wise for me to remember that I am probably not like all of my students in another way: I just love to write code.

    One of my great joys as an instructor is to come across a student, or even a class full of students, who love to write code. I enjoy working with them in class, and on independent projects, and on undergraduate research. I learn from them, and I hope they learn a little from me along the way:

    Ultimately we learn best by placing our confidence
    in men and women whose examples invite us
    to love what they love.
    -- Robert Wilken

    One thing is certain. I love to write code.


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

    November 12, 2006 11:34 AM

    Practice What I Preach

    One of my colleagues occasionally comments that many of the folks in our department don't often practice in the rest of our professional lives what we preach in our areas of technical expertise. For example, in software engineering we often speak of the importance of gathering requirements, writing a complete specification, and then later testing our product to ensure that it meets the spec. But CS faculty are often reluctant to practice these ideas in the context of curriculum and departmental mission, which leads to a lack of motivation for tasks such as academic program review both on the side of specifying concrete department goals and concrete course competencies and on the side of measuring outcomes.

    My colleague's observation is usually true. Expertise doesn't transfer very well across domains of practice; and, even when the mindset transfers, the practices and habits don't. It takes a lot of work to translate the mindset into the new habits we need in the new domain, and we have to watch out for pitfalls that let us convince ourselves that the new domain is so different that we can't practice what we preach.

    Though my colleague has never made his observation to me when commenting on my performance, I know well that I am guilty. I strongly encourage the use of agile methods in software development, and I've even written in this space on how I have intended to "be agile" in how I approach my administrative duties. But as I look back over my first fifteen months as a department head, I see a path littered with good intentions leading to a very different place than I wanted to be.

    Cast of 'One Day at a Time'

    I had hoped to write a retrospective of my first year in the Big Office by now, but I haven't yet -- in part because I don't feel I have synthesized much of an understanding of what I do yet, but also in part, I think, because I feel a bit ashamed of my weaknesses. I haven fallen woefully behind on several major projects, including ones that were centerpieces of my desire to become head. As I look back, I see many of the signature problems of big software projects falling behind. As Fred Brooks tells us in The Mythical Man-Month, how do disastrously late projects get that way? "One day at a time." When I fall farther behind, it is rarely because a major task preempts my time; most of the slippage in my schedule results from "termites" -- little interruptions, small distractions, and bad decisions made in the small.

    I am agile in mindset, but not in practice. How can I change that? Go back to the basics: Define small tasks. Define "tests" that will help me know that I have made concrete progress. Release small deliverables frequently to the folks who depend on my work, especially the faculty.

    I know what to do. Now it is time to get serious about new practices for the new tasks I tackle.


    Posted by Eugene Wallingford | Permalink | Categories: Managing and Leading, Software Development

    October 28, 2006 8:05 PM

    OOPSLA This and That

    In addition to the several OOPSLA sessions I've already blogged about, there were a number of other fun or educational moments at the conference. Here are a few...

  • Elisa Baniassad presented an intriguing Onward! talk called The Geography of Programming. She suggested that we might learn something about programming language design by considering the differences between Western and Eastern thought. Her motivation came from Richard Nisbett's The Geography of Thought: How Asians and Westerners Think Differently--And Why. One more book added to my must-read list...

  • Partly in honor of OOPSLA stalwart John Vlissides, who passed away since OOPSLA'05, and partly in honor of Vlissides et al.'s seminal book Design Patterns, there was a GoF retrospective panel. I learned two bits of trivia... John's favorite patterns were flyweight (which made it into the book) and solitaire (which didn't). The oldest instance of a GoF pattern they found in a real system? Observer -- in Ivan Sutherland's SketchPad! Is anyone surprised that this pattern has been around that long, or that Sutherland discovered its use over 40 years ago? I'm not.

  • On the last morning of the conference, there was scheduled a panel on the marriage of XP and Scrum in industry. Apparently, though, before I arrived on the scene it had morphed into something more generally agile. While discussing agile practices, "Object Dave" Thomas admitted he believes that, contrary to what many agilists seem to imply, comments in code are useful. After all, "not all code can be read, being encrypted in Java or C++ as it is". But he then absolved his sin a bit by noting that the comment should be "structurally attached" to the code with which it belongs; that is a tool issue.

  • Then, on the last afternoon of the conference, I listened in on the Young Guns panel, in which nearly a dozen computer scientists under the age of 0x0020 commented on the past, present, and future of objects and computing. One of these young researchers commented that scientists tend to make their great discoveries while still very young, because they don't yet know what's impossible. To popularize this wisdom, gadfly and moderator Brian Foote suggested a new motto for our community: "Embrace ignorance."

  • During this session, it occurred to me that I am no longer a "young gun" myself, spending the six last days of my 0x0029th year at OOPSLA. This is part of how I try to stay "busy being born", and I look forward to it every year. I certainly don't feel like an old fogie, at least not often.

  • Finally, as we were wrapping up the conference in the committee room after the annual ice cream social, I told Dick Gabriel that I would walk across the street to hear Guy Steele read a restaurant menu aloud. Maybe there is a little bit of hero worship going on here, but I always seem to learn something when Steele shares his thoughts on computing.

    ----

    Another fine OOPSLA is in the books. The 2007 conference committee is already at work putting together next year's event, to be held in Montreal during the same week. Wish us wisdom and good fortune!


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

    October 28, 2006 7:36 PM

    OOPSLA Day 3: Philip Wadler on Faith, Evolution, and Programming Languages

    Philip Wadler

    "Of course, the design should be object-oriented." Um. "Of course not. The design should be functional". Day 3's invited speaker, Philip Wadler, is a functional programming guy who might well hear the first statement here at OOPSLA, or almost anywhere out in a world where Java and OO have seeped through the software development culture, and almost as often he reacts with the second statement (if only in his mind). He has come to recognize that these aren't scientific statements or reactions; they are matters of faith. But faith and science as talking about different things. Shouldn't we make language and design choices on the basis of science? Perhaps, but we have a problem: we have not yet put our discipline on a solid enough scientific footing.

    The conflict between faith and science in modern culture, such as on the issue of evolution, reminds Wadler of what he sees in the computing world. Programming language design over the last fifty years has been on an evolutionary roller coaster, with occasional advances injected into path of languages growing out of the dominant languages of the previous generation. He came to OOPSLA in a spirit of multiculturalism, to be a member of a "broad church", hoping to help us see the source of his faith and to realize that we often have alternatives available when we face language and design decisions.

    The prototypical faith choice that faces every programmer is static typing versus dynamic typing. In the current ecosystem, typing seems to have won out versus no typing, static typing has usually had a strong upper hand over dynamic typing. Wadler reminded us that this choice goes back to the origins of our discipline, between the untyped lambda calculus of Alonzo Church and the typed calculus of Haskell Curry. (Church probably did not know he had a choice; I wonder how he would have decided if he had?)

    Wadler then walked us through his evolution as a programming languages researcher, and taught us a little history on the way.

    Church: The Origins of Faith

    Symbolic logic was largely the product of the 19th century mathematician Gottlob Frege. But Wadler traces the source of his programming faith to the German logician Gerhard Gentzen (1909-1945). Gentzen followed in footsteps of Frege, both as a philosopher of symbolic logic and as an anti-Semite. Wadler must look past Gentzen's personal shortcomings to appreciate his intellectual contribution. Gentzen developed the idea of natural deduction and proof rules.

    (Wadler showed us page of inference rules using the notation o mathematical logic, and then asked for a show of hands to see if we understood the ideas and the notation on his slides. On his second question, enough of the audience indicated uncertainty that he slowed down to explain more. He said that he didn't mind the diversion: "It's a lovely story.")

    Next he showed the basics of simplifying proofs -- "great stuff", he old us, "at least as important as the calculus", something man had searched for thousands of years. Wadler's love for his faith was evident in the words he chose and the conviction with which he said them.

    Next came Alonzo Church, who did his work after Gentzen but still in the first half of the 20th century. Church gave us the lambda calculus, from which the typed lambda calculus was "completely obvious" -- in hindsight. The typed lambda calculus was all we needed to make the connection between logic and programming: a program is a proof, and a type is a proof term. This equivalence is demonstrated in the Curry-Howard isomorphism, named for the logician and computer scientist, respectively, who made the the connection explicit. In Wadler's view, this isomorphism predicts that logicians and computer scientists will develop many of the same ideas independently, discovered from opposite sides of the divide.

    This idea, that logic and programming are equivalent, is universal. In the movie, Independence Day, the good guys defeat the alien invaders by injecting a virus written in C into its computer system. The aliens might not have known the C programming language, and thus been vulnerable on that front, but they would have to have known the lambda calculus!

    Haskell: Type Classes

    The Hindley-Milner algorithm is named for another logician/computer scientist pair that made the next advance in this domain. They showed that even without type annotations an automated system can deduce the most general data types that make the program execute. The algorithm is both correct and complete. Wadler wanted to show us that this idea is so important, so beautiful, that he took a step to the side of his podium and jumped up and down!

    Much of Wadler's renown in the programming language derives from his seminal contributions to Haskell, a pure functional language based on Curry-Howard isomorphism and the Hindley-Milner algorithm. Haskell implements these ideas in the form of type classes. Wadler introduced this idea into the development of Haskell, but he humbly credited others for doing the hard work to make things work.

    Java: Adding Generics

    Java 1.4 was in many ways too simple. We had to use a List of some sort for almost everything, in order to have polymorphic structures. Trying to add C-style templates threatened to make things only worse. What the Java team needed was... the lambda calculus!

    (At this moment, Wadler stopped his talk Superman-style and took off his business suit to reveal his Lambda-man outfit. The crowd responded with hearty applause!)

    Philip Wadler as 'Lambda Man'

    Java generics have the same syntax as C++, but different semantics. (He added parenthetically that Java generics "have semantics".) The templates are merely syntactic sugar, rewritten into older Java in a technique called "erasure". The rewrite produces identical byte codes that a programmer's own Java might. Much was written about this language addition both before and after he it was made to the Java specification, and I don't want to get into that discussion. But, as Wadler notes, this approaches supports the evolution of the language in a smooth way, consistent with existing Java practice. Java generics also bear more than a passing resemblance to type classes, which means that it could evolve into something more different -- and more.

    Links: Reconciliation

    Web applications typically consist in three tiers: the browser, the server, and the database. All are typically programmed in different languages, such as HTML, CSS, JavaScript, Perl, and SQL. Wadler's newest language, Links, is intended to be one language used for all three tiers. It compiles to SQL for running directly against a database. Links is similar to the similar-sounding LINQ, a dynamic query language developed at Microsoft. The similarity is no coincidence -- one of its architects, Erik Meijer, came from Haskell community. Again, type classes figure prominently in Links. Programmers in the OO community can think of them in an OO way with no loss of understanding. But they may want to broaden their faith to include something more.

    Wadler closed his talk by returning to the themes with which he began: faith, evolution, and multiculturalism. He viewed the OOPSLA conference committee's inviting him to speak as a strong ecumenical step. "Faith is well and good", but he would like for computer science to make inroads helping us to make better decisions about language design and use. Languages like Links, implemented with different features and used in experiments, might help.


    Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

    October 26, 2006 4:28 PM

    OOPSLA Day 2: Jim Waldo "On System Design"

    Last year, OOPSLA introduced another new track called Essays. This track shared a motivation from another recent introduction, Onward!, in providing an avenue for people to write and present important ideas that cannot find a home in the research-oriented technical program of the usual academic conference. But not all advances are in the form of novelty, of results from narrowly-defined scientific experiments. Some empirical results are the fruit of experience, reflection, and writing. The Essays track offers an avenue for sharing this sort of learning. The author writes an essay in the spirit of Montaigne and Bacon, using the writing to work out an understanding of his experience. He then presents the essay to the OOPSLA audience, followed by a thoughtful response from a knowledge person who has read the essay and thought about the ideas. (Essays crossed my path in a different arena last week, when I blogged a bit on the idea of blog as essay.)

    Jim Waldo, a distinguished engineer at Sun, presented the first essay of OOPSLA 2006, titled "On System Design". He reflected on his many years as a software developer and lead, trying to get a handle on what he now believes about the design of software.

    What is a "system"? To Waldo, it is not "just a program" in the sense he thinks meant by the postmodern programming crowd, but a collection of programs. It exists at many levels of scale that must be created and related; hence the need for us to define and manage abstractions.

    Software design is a craft, in the classical sense. Many of Waldo's engineer friends are appalled at what software engineers think of as engineering (essentially the application of patterns to roll out product in a reliable, replicable way) because what engineers really do involves a lot of intuition and craft.

    Software design is about technique, not facts. Learning technique takes time, because it requires trial and error and criticism. It requires patience -- and faith.

    Waldo paraphrase Grady Booch as having said that the best benefit of the Rational toolset was that it gives developers "a way to look like they were doing something while they had time to think".

    The traditional way to learn system design is via apprenticeship. Waldo usually asks designers he respects who they apprenticed with. At first he feared that at least a few would look at him oddly, not understanding the question. But he was surprised to find that every person answered without batting an eye. They all not only understood the question but had an immediate answer. He was also surprised to hear the same few names over and over. This may reflect Waldo moving in particular circles, or only a small set of master software developers out there!

    In recent years, Waldo has despaired of the lack of time, patience, and faith shown in industry for developing developers. Is all lost? No. In reflecting on this topic and discussing with readers of his early drafts, Waldo sees hope in two parts of the software world: open source and extreme programming.

    Consider open source. It has a built-in meritocracy, with masters at the top of the pyramid, controlling the growth and design of their systems. New developers learn from example -- the full source of the system being built. Developers face real criticism and have the time and opportunity to learn and improve.

    Consider extreme programming. Waldo is not a fan of the agile approaches and doesn't think that the features on which they are sold are where they offer most. It isn't the illusion of short-term cycles or of the incrementalism that grows a big ball of mud which give him hope. In reality, the agile approaches are based in a communal process that builds systems over time, giving people the time to think and share, mentor and learn. Criticism is built into the process. The system is an open, growing example.

    Waldo concludes that we can't teach system design in a class. As an adjunct professor, he believes that system design skills aren't a curriculum component but a curricular outcome. Brian Marick, the discussant on Waldo's took a cynical turn: No one should be allowed to teach students system design if they haven't been a committer to a large open-source project. (Presumably, having had experience building "real" big systems in another context would suffice.) More seriously, Marick suggested that it is only for recent historical reasons that we would turn to academia to solve the problem of producing software designers.

    I've long been a proponent of apprenticeship as a way of learning to program, but Waldo is right that doing this as a part of the typical university structure is hard, if not impossible. We heard about a short-lived attempt to do this at last year's OOPSLA, but a lot of work remains. Perhaps if more people like Waldo, not just the more provocative folks at OOPSLA, start talking openly about this we might be able to make some progress.

    Bonus reading reference: Waldo is trained more broadly as a philosopher, and made perhaps a surprising recommendation for a great document on the act of designing a new sort of large system: The Federalist Papers. This recommendation is a beautiful example of the value in a broad education. The Federalist Papers are often taught in American political science courses, but from a different perspective. A computer scientist or other thinker about the design of systems can open a whole new vista on this sort of document. Here's a neat idea: a system design course team taught by a computer scientist and a political scientist, with The Federalist Papers as a major reading!

    Now, how to make system design as a skill an inextricable element of all our courses, so that an outcome of our major is that students know the technique? ("Know how", not "know that".)


    Posted by Eugene Wallingford | Permalink | Categories: Computing, Patterns, Software Development

    October 26, 2006 3:46 PM

    OOPSLA Day 2: Guy Steele on Fortress

    The first two sentences of Guy Steele's OOPSLA 2006 keynote this morning were eerily reminiscent of his describes the application of the principles from his justly famous OOPSLA 1998 invited talk Growing a Language. I'm pretty sure that, for that few seconds, he used only one-syllable words!

    Guy Steele

    This talk, A Growable Language, was related to that talk, but in a more practical sense. It applied the spirit and ideas expressed in that talk to a new language. His team at Sun is designing Fortress, a "growable language" with the motto "To Do for Fortran What Java Did for C".

    The aim of Fortress is to support high-performance scientific and engineering programming without carrying forward the historical accidents of Fortran. Among the additions to Fortran will be extensive libraries, including for networking, a security model, type safety, dynamic compilation (to enable the optimization of running program), multithreading, and platform independence. The project is being funded by DARPA with the goal of improving programmer productivity for writing scientific and engineering applications -- to reduce the time between when a programmer receives a problem and when the programmer delivers the answer, rather than focus solely on the speed of the compiler or executable. Those are important, too, but we are shortsighted in thinking that they are the only formsof speed that matter. (Other DARPA projects in this vein are the Extend language from IBM[?] and the Chapel language from Cray.)

    Given that even desktop computers are moving toward multicore chips, this sort of project offers potential value beyond the scientific programming community.

    The key ideas behind the Fortress project are threefold:

    • Don't build a language; grow it piecemeal.
    • Create a programming notation that is more like the mathematical notation that this programmer community uses.
    • Make parallelism the default way of thinking.

    Steele reminded his audience of the motivation for growing a language from his first talk: If you plan for a language, and then design it, then build it, you will probably miss the optimal window of opportunity for language. One of the guiding questions of the Fortress project is, Will designing for the growth of a language and its user community change the technical decisions the team makes or, more importantly, the way it makes them?

    One of the first technical questions the team faced was what set of primitive data types to build into the language. Integer and float -- but what sizes? Data aggregates? Quaternions, octonions? Physical units such as meter and kilogram?? He "might say 'yes' to all of them, but he must say no to some of them." Which ones -- and why?

    The strategy of the team is to, wherever possible, add a desired feature via a library -- and to give library designers substantial control over both the semantics and the syntax of the library. The result is a two-level language design: a set of features to support library designers and a set of features to support application programmers. The former have turned out to be quite obbject-oriented, while the latter is not obbject-oriented at all -- something of a surprise to the team.

    At this time, the language defines some very cool types in libraries: lists, vectors, sets, maps (with better, more math-like notion), matrices and multidimensional vectors, and units of measurement. The language also offers as a feature mathematical typography, using a wiki-style mark-up to denote Unicode characters beyond what's available on the ASCII keyboard.

    In the old model for designing a language, the designers

    • study applications
    • add language features to support application developers
    In the new model, though, designers
    • study applications
    • add language features to support library designers in creating the desired features
    • let library designers create a library that supports application developers

    At a strategic level, the Fortress team wants to avoid creating a monolithic "standard library", even when taking into account the user-defined libraries created by a single team or by many. Their idea is instead to treat libraries as replaceable components, perhaps with different versions. Steele says that Fortress effectively has make and svn built into its toolset!

    I can just hear some of my old-school colleagues decrying this "obvious bloat", which must surely degrade the language's performance. Steele and his colleagues have worked hard to make abstraction efficient in a way that surpasses many of today's languages, via aggressive static and dynamic optimization. We OO programmers have come to accept that our environments can offer decent efficiency while still having features that make us more productive. The challenge facing Fortress is to sell this mindset to C and Fortran programmers with habits of 10, 20, even 40 years thinking that you have to avoid procedure calls and abstract data types in order to ensure optimal performance.

    The first category of features in Fortress intend to support library developers. The list is an impressive integration of ideas from many corners of the programming language community, including first-class types, traits and trait descriptors (where, comprise, exclude), multiple inheritance of code but not fields, and type contracts. In this part of the language definition, knowledge that used to be buried in the compiler is brought out explicitly into code where it can be examined by programmers, reasoned over by the type inference system, and used by library designers. But these features are not intended for use by application programmers.

    In order to support application developers, Steele and his team watched (scientific) programmers scribble on their white boards and then tried to convert as much of what they say as possible into their language. For example, Fortress takes advantage of subtle whitespace cues, as in phrases such as

    { |x| | x ← S, 3 | x }

    Note the four different uses of the vertical bar, disambiguated in part by the whitespace in the expression.

    The wired-in syntax of Fortress consists of some standard notation from programming and math:

    • () for grouping
    • , for separating values in a tuple
    • ; for separating statements on a line
    • . for selecting fields and methods
    • conservative, traditional rules of precedence

    Any other operator can be defined as infix, prefix, or postfix. For example, ! is defined as a postfix for factorial. Similarly, juxtaposition is a binary operator, one which can be defined by the library designer for her own types. Even nicer for the cientific programmer, the compiler knows that the juxtaposition of functions is itself a function (composition!).

    The syntax of Fortress is rich and consistent with how scientific programmers think. But they don't think much about "data types", and Fortress supports that, too. The goal is for library designers to think about types a lot, but application programmers should be able to do their thing with type inference filling in most of the type information.

    Finally, scientists, engineers, and mathematicians use particular textual conventions -- fonts, characters, layout -- to communicate. Fortress allows programmers to post-process their code into a beautiful mathematical presentation. Of course, this idea and even its implementation are not new, but the question for the Fortress team was what it would be like if a language were designed with this downstream presentation as the primary mode o presentation?

    The last section of Steele's talk looked a bit more like a POPL or ICFP paper, as he explained the theoretical foundations underlying Fortress's biggest challenge: mediating the language's abstractions down to efficient executable code for parallel scientific computation. Steele asserted that parallel programming is not a feature but rather a pragmatic compromise. Programmers do not think naturally in parallel and sop need language support. Fortress is an experiment in making parallelism the default mode of computation.

    Steele's example focused on the loop, which in most languages conflates two ideas: "do this statement (or block) multiple times" and "do things in this order". In Fortress, the loop itself means only the former; by default its iterations can be parallelized. In order to force sequencing, the programmer modifies the interval of the loop (the range of values that "counts" the loop) with the seqoperator. So, rather than annotate code to get parallel compilation, we must annotate to get sequential compilation.

    Fortress uses the idea of generators and reducers -- functions that produce and manipulate, respectively, data structures like sequences and trees -- as the basis of the program transformations from Fortress source code down to executablecode. There are many implementations for these generators and reducers, some that are sequential and some that are not.

    From here Steele made a "deep dive" into how generators and reducers are used to implement parallelism efficiently. That discussion is way behind what I can write here. Besides, I will have to study the transformations more closely before I can explain them well.

    As Steele wrapped up, he reiterated The Big Idea that guides the Fortress team: to expose algorithm and design decisions in libraries rather than bury them in the compiler -- but to bury them in the libraries rather than expose them in application code. It's an experiment that many of us are eager to see run.

    One question from the crowd zeroed in on the danger of dialect. When library designers are able to create such powerful extensions, with different syntactic notations, isn't there a danger that different libraries will implement similar ideas (or different ideas) incompatibly? Yes, Steele acknolwedge, that is a real danger. He hopes that the Fortress community will grow with library designers thinking of themselves as language designers and so exercise restraint in the the extensions they make, and work together to create community standards.

    I also learned about a new idea that I need to read about... the BOOM hierarchy. My memory is vagues, but the discussion involved considering whether a particular operation -- which, I can't remember -- is associative, commutative, and idempotent. There are, of course, eight possible combinations of these features, four of which are meaningful (tree, list, bag/multiset, and set). One corresponds to an idea that Steele termed a "mobile", and the rest are, in his terms, "weird". I gotta read more!


    Posted by Eugene Wallingford | Permalink | Categories: Computing, Patterns, Software Development

    October 25, 2006 2:13 PM

    OOPSLA Day 1: Gabriel and Goldman on Conscientious Software

    The first episode of Onward! was a tag team presentation by Ron Goldman and Dick Gabriel of their paper Conscientious Software. The paper is, of course, in the proceedings and so the ACM Digital Library, but the presentation itself was performance art. Ron gave his part of the talk in a traditional academic style, dressed as casually as most of the folks in the audience. Dick presented an outrageous bit of theater, backed by a suitable rock soundtrack, and so dressed outrageously (for him) in a suit.

    In the "serious" part of the talk, Ron spoke about complexity and scale, particularly in biology. His discussion of protein, DNA, and replication soon turned to how biological systems suffer damage daily to their DNA as a natural part of their lifecycle. They also manage to repair themselves, to return to equilibrium. These systems, Ron said, "pay their dues" for self-repair. Later he discussed chemotaxis in E.Coli, wherein "organisms direct their movements according to certain chemicals in their environment". This sort of coordinated but decentralized action occurs not among a bacterium's flagella but also among termites as they build a system, and elephants as they vocalize across miles of open space, and among chimpanzees as they pass emotional state via facial expression.

    We have a lot to learn from living things as we write our programs.

    What about the un-"serious" part of the talk? Dick acted out a set of vignettes under title slides such as "Thirteen on Visibility", "Continuous (Re)Design", "Requisite Variety", and "What We Can Build".

    His first act constructed a syllogism, drawing on the theme that the impossible is famously difficult. Perfect understanding requires abstraction, which is the ability to see the simple truth. Abstraction ignores the irrelevant. Hence abstraction requires ignorance. Therefore, perfect understanding requires ignorance.

    In later acts, Dick ended up sitting for a while, first listening to his own address was part of the recorded soundtrack and then carrying on a dialogue with his alter ego, which spoke in a somewhat ominous Darth Vader-ized voice in counterpoint. The alter ego espoused a standard technological view of design and modularity, of reusable components with function and interface. This left Gabriel himself to embody a view centered on organic growth and complexity -- of constant repair and construction.

    Dick's talk considered Levittown and the intention of "designed unpredictability", even if inconvenient, such as the placement of the bathroom far from the master bedroom. In Levittown, the 'formal cause' (see my notes on Brenda Laurel's keynote from the preceding session) lay far outside the "users", in Levitt's vision of what suburban life should be. But today Levittown is much different than designed; it is lived-in, a multi-class, multi-ethnic community that bears "the complexity of age".

    On requisite variety, Dick started with a list of ideas (including CLOS, Smalltalk, Self, Oaklisp, ...) disappearing one by one to the background music of Fort Minor's Where'd You Go.

    The centerpiece of Gabriel's part of the talk followed a slide that read

    Ghazal
    (google it)
    on
    "Unconventional Design"

    He described an experiment in the artificial evolution of electronic circuits. The results were inefficient to our eyes, but they were correct and carried certain advantages we might not expect from a human-designed solution. The result was labeled "... magical ... unexpected ...". This sort system building is reminiscent of what neural networks promise in the world of AI, an ability to create (intelligent) systems without having to understand the solution at all scales of abstraction. For his parallel, Dick didn't refer to neural nets but to cities -- they are sometimes designed; their growth is usually governed; and they are built (and grow) from modules: a network of streets, subways, sewers.

    Dick closed his talk with a vignette whose opening slide read "Can We Get There From Here" (with a graphical flourish I can't replicate here). The coming together of Ron's and Dick's threads suggest one way to try: find inspiration in biology.


    Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

    October 24, 2006 11:31 PM

    OOPSLA Day 1: Brenda Laurel on Designed Animism

    Brenda Laurel

    Brenda Laurel is well known in computing, especially the computer-human interaction computing, for her books The Art of Human-Computer Interface Design and the iconic Computers as Theatre. I have felt a personal connection to her for a few years, since an OOPSLA a few years ago when I bought Brenda's Utopian Entrepreneur, which describes her part in starting Purple Moon, a software company to produce empowering computer games for young girls. That sense of connection grew this morning as I prepared this article, when I learned that Brenda's mom is from Middletown, Indiana, less than an hour from my birthplace, and just off the road I drove so many times between my last Hoosier hometown and my university.

    Laurel opened this year's OOPSLA as the Onward! keynote speaker, with a talk titled, "designed animism: poetics for a new world". Like many OOPSLA keynotes, this one covered a lot of ground that was new to me, and I can remember only a a bit -- plus what I wrote down in real time.

    These days, Laurel's interests lie in pervasive, ambient computing. (She recently gave a talk much like this one at UbiComp 2006.) Unlike most folks in that community, her goal is not ubiquitous computing as primarily utilitarian, with its issues of centralized control, privacy, and trust. Her interest is in pleasure. She self-effacingly attributed this move to the design tactic of "finding the void", the less populated portion of the design space, but she need not apologize; creating artifacts and spaces for human enjoyment is a noble goal -- a necessary part of of our charter -- in its own right. In particular, Brenda is interested in the design of games in which real people are characters at play.

    Dutch Windmill Near Amsterdam, Owen Merton, 1919

    (Aside: One of Brenda's earliest slides showed this painting, "Dutch Windmill Near Amsterdam" by Owen Merton (1919). In finding the image I learned that Merton was the father of Thomas Merton, the Buddhist-inspired Catholic monk whom I have quoted here before. Small world!)

    Laurel has long considered how we might extend Aristotle's poetics to understand and create interactive form. In the Poetics, Aristotle "set down ... an understanding of narrative forms, based upon notions of the nature and intricate relations of various elements of structure and causation. Drama relied upon performance to represent action." Interactive systems complicate matters relative to Greek drama, and ubiquitous computing "for pleasure" is yet another matter altogether.

    To start, drawing on Aristotle, I think, Brenda listed the four kinds of cause of a created thing (at this point, we were thinking drama):

    • the end cause -- its intended purpose
    • the formal cause -- the platonic ideal in the mind of the creator that shaped the creation
    • the efficient cause -- the designer herself
    • the material cause -- the stuff out of which it is made, which constrains and defines the thing

    In an important sense, the material and formal causes work in opposite directions with respect to dramatic design. The effects of the material cause work bottom-up from material to pattern on up to the abstract sense of the thing, while the effects of the formal cause work top-down from the ideal to components on to the materials we use.

    Next, Brenda talked about plot structure and the "shape of experience". The typical shape is a triangle, a sequence of complications that build tension followed by a sequence of resolutions that return us to our balance point. But if we look at the plots of most interesting stories at a finer resolution, we see local structures and local subplots, other little triangles of complication and resolution.

    (This part of the talk reminded of a talk I saw Kurt Vonnegut give at UNI almost a decade or so ago,in which he talked about some work he had done as a master's student in sociology at the University of Chicago, playfully documenting the small number of patterns that account for almost all of stories we tell. I don't recall Vonnegut speaking of Aristotle, but I do recall the humor in is own story. Laurel's presentation blended bits of humor with two disparate elements: an academic's analysis and attention to detail, and a child's excitement at something that clearly still lights up her days.)

    One of the big lessons that Laurel ultimately reaches is this: There is pleasure in the pattern of action. Finding these parts is essential to telling stories that give pleasure. Another was that by using natural materials (the material causality in our creation), we get pleasing patterns for free, because these patterns grow organically in the world.

    I learned something from one of her examples, Johannes Kepler's Harmonices Mundi, an attempt to "explain the harmony of the world" by finding rules common to music and planetary motion within the solar system. As Kepler wrote, he hoped "to erect the magnificent edifice of the harmonic system of the musical scale ... as God, the Creator Himself, has expressed it in harmonizing the heavenly motions." In more recent times, composers such as Stravinsky, deBussy, and Ravel have tried to capture patterns from the visual world in their music, seeking more universal patterns of pleasure.

    This led to another of Laurel's key lessons, that throughout history artists have often captured patterns in the world on the basis of purely phenomenological evidence, which were later reified by science. Impressionism was one example; the discovery of fractal patterns in Jackson Pollock's drip projectories were another.

    The last part of Laurel's talk moved on to current research with sensors in the ubiquitous computing community, the idea of distributed sensor networks that help us to do a new sort of science. As this science exposes new kinds of patterns in the about the world, Laurel hopes for us to capitalize on the flip side of the art examples before: to be able to move from science, to math, and then on to intuition. She would like to use what we learn to inform the creation of new dramatic structures, of interactive drama and computer games that improve the human condition -- and give us pleasure.

    The question-and-answer session offered a couple of fun moments. Guy Steele asked Brenda to react to Marvin Minsky's claim that happiness is bad for you, because once you experience it you don't want to work any more. Brenda laughed and said, "Marvin is a performance artist." She said that he was posing with this claim, and told some stories of her own experiences with Marvin and Timothy Leary (!). And she is even declared a verdict in my old discipline of AI: Rod Brooks and his subsumption architecture are right, and Minsky and the rest of symbolic AI are wrong. Given her views and interests in computing, I was not surprised by her verdict.

    Another question asked whether she had seen the tape of Christopher Alexander's OOPSLA keynote in San Jose. She hadn't, but she expressed a kinship in his mission and message. She, too, is a utopian and admitted to trying to affect our values with her talk. She said that her research through the 1980s especially had taught her how she could sell cosmetics right into the insecurities of teenage girls -- but instead she chose to create an "emotional rehearsal space" for them to grow and overcome those insecurities. That is what Purple Moon was all about!

    As usual, the opening keynote was well worth our time and energy. As a big vision for the future, as a reminder of our moral center, it hit the spot. I'm still left to think how these ideas might affect my daily work as teacher and department leader.

    (I'm also left to track down Ted Nelson's Computer Lib/Dream Machines, a visionary, perhaps revolutionary book-pair that Laurel mentioned. I may need the librarian's help for this one.)


    Posted by Eugene Wallingford | Permalink | Categories: Computing, Patterns, Software Development

    October 23, 2006 11:51 PM

    OOPSLA Educators' Symposium 1: Bob Martin on OOD

    Unlike last year, the first day of OOPSLA was not an intellectual charge for me. As tutorials chair, I spent the day keeping tabs on the sessions, putting out small fires involving notes and rooms and A/V, and just hanging out. I had thought I might sneak into the back of a technical workshop or a educational workshop, but my time and energy were low.

    Today was the Educators' Symposium, my first since chairing in 2004 and 2005. I enjoyed not having to worry about the schedule or making introductions. The day held a couple of moments of inspiration for me, and I'll write about at least one -- on teaching novices to design programs -- later.

    Uncle Bob Martin

    The day's endpoint was an invited talk by Robert Uncle Bob Martin. In a twist, Bob let us choose the talk we wanted to hear: either his classic "Advanced Principles of Object-Oriented Class Design" or his newer and much more detailed "Clean Code".

    While we thought over our options, Martin started with a little astronomy lesson that involved Henrietta Levitt, globular clusters, distance calculations, and the width of our galaxy. Was this just filler? Was there a point related to software? I don't know. Maybe Bob just likes telescopes.

    The vote of the group was for Principles. Sigh. I wanted Clean Code. I've read all of Bob's papers that underlie this talk, and I was in the mood for digging into code. (Too many hours pushing papers and attending meetings will do that to a guy who is Just a Programmer at heart.)

    But this was good. With some of the best teachers, reading a paper is no substitute for the performance art of a good presentation. This blog can't recreate the talk, so if you already know Martin's five principles of OO design, you may want to move on to his latest ruminations on naming.

    At its core, object-oriented design is about managing dependencies in source code. It aims to circumvent the problems inherent in software with too many dependencies: rigidity, fragility, non-reusability, and high viscosity.

    Bob opened with a simple but convincing example of a copy routine, a method that echoes keyboard input to a printer, to one of his five principles, the Dependency Inversion Principle. In procedural code, dependency flows from the top down in a set of modules. In OO code, there a point where top-down dependencies end at an abstraction like an interface, and the dependencies begin to flow up from the details to the same abstractions. My favorite detail in this example was his pointing out that getch() is polymorphic method, programmed to the abstractions of standard input and standard output. ("Who needs all that polymorphism nonsense," say my C-speaking colleagues. "Let's teach students the fundamentals from the bottom up." Hah!)

    Martin then went through each of his five principles, including DIP, with examples and a theatrical interaction with his audience. Here are the highlights to me:

    • In the Single Responsibility Principle, a class should have one and only one reason to change.

      Side lesson: There is no perfect way to write code. There are always competing forces. There is a conflict between the design principle encapsulation and the SRP. To ensure the SRP, we may need to relax encapsulation; to ensure encapsulation, we may need to relax the SRP. How to choose? All other things equal, we should prefer the SRP, as it protects us from a clear and present danger, rather than from potential bad behavior of programmers working with our code in the future. A mini-sermon on overprotective languages and practices followed. The Smalltalk programmers in the audience surely recognized the theme.

    • The Open/Closed Principle states that a class should be open for extension and closed for modification. The idea is that any change to behavior should be implemented in new code, not in changes to existing code.

      Side lesson: OO design works best if you can predict the future, so that you can select the abstractions which are likely to change. We can predict the future (or try) either by thinking hard or by letting customers use early versions of the code and reacting to the actual changes they cause. Ceteris paribus, OO design may be better than the alternatives, but it still requires work to get right.

    • The Liskov Substitution Principle is the formal name for one of the central principles of my second-course OO programming course over the last decade, which I have usually called "substitutability". We should be able to drop an instance of a subclass into a variable typed to a superclass -- and not have the client know the difference. In practice, we recognize violations of the LSP when we see limitations in subclasses such as overriding methods throwing exceptions.

    • Of all Martin's principles, the one I tend to teach and consider consciously least often is the Integration Segregation Principle. Rather than writing classes that depend on a "fat" class that offers many services, we should segregate clients into sets according to their thinner needs by means of interfaces.

    • Finally, we return to the Dependency Inversion Principle. In some ways, this is the most basic of the design ideas in Martin's cadre, and it is the one by which we can often recognize OO pretenders from those who really get it. Details in our programs should depend on abstractions, not the other way around. If you call a method, create a subclass, override a method ... you wish the depended-on method or class to be abstract. Abstractions hide the client code from changes that almost necessarily follow concrete implementations.

      Side lesson: Another conflict we face when we program is that between flexibility and type safety. As with the SRP and encapsulation, to achieve one of flexibility and type safety in practice, we often have to relax the other. Martin described how the trend toward test-driven design and full-coverage unit testing eliminates many of the compelling reasons for us to seek type safety in a language. The result is that in this competition between forces we can favor flexibility as our preferred goal -- and choose the languages we use differently! Ruby, Python, duck typing... these trends signal our ability to choose empowering, freeing languages as long as we are willing to achieve the value of type safety through the alternate means of tests.

    The talk just ended with no summary or conclusion, probably due to us being short on time. Martin had been generous with his audience interaction throughout, asking and answering questions and playfully enjoying all comments. The talk really was quite good, and I can see how he has become one of the top draws on the OO speaking circuit. At times he sounded like a preacher, moving and intoning in the rhythms of a revival minister. Still, one of his key points was that OO as religion isn't nearly as compelling as OO as proven technique for building better software.

    The teacher in me left the symposium feeling a little bit second-best. How might I speak and teach classes in a way that draws such rapt interest from my audience? Could I teach more effectively if I did? The easy answer is that this is just not my style, but that may be an excuse. Can I -- should I -- try to change? Or should I just try to maximize what I do well? (And just what is that?)


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

    October 13, 2006 11:00 AM

    Student Entrepreneurship -- and Prosthetics?

    Technology doesn't lead change.
    Need leads change.

    -- Dennis Clark, O&P1

    This morning I am hanging out at a campus conference on Commercializing Creative Endeavors. It deals with entrepreneurship, but from the perspective of faculty. As a comprehensive university, not an R-1 institution, we tend to generate less of the sort of research that generates start-ups. But we do have those opportunities, and even more so the opportunity to work with local and regional industry.

    The conference's keynote speaker is Dennis Clark, the president of O&P1, an local orthotics and prosthetics company that is doing amazing work developing more realistic prosthetics. His talk focused on his collaboration with Walter Reed Army Medical Center to augment amputees from the wars in Afghanistan and Iraq. It is an unfortunate truth that war causes his industry to advance, in both research and development. O&P1's innovations include new fabrication techniques, new kinds of liners and sensors, and shortened turnaround times in the design, customization, fabrication, and fitting prosthetics for specific patients.

    Dennis has actively sought collaborations with UNI faculty. A few years ago he met with a few of us in computer science to explore some project ideas he had. Ultimately, he ended up working closely with two professors in physics and physical education on a particular prosthetics project, specifically work with the human gait lab at UNI, which he termed "world-class". That we have a world-class gait lab here at UNI was news to me! I have never worked on human gait research myself, though I was immediately reminded of some work on modeling gait by folks in Ohio State's Laboratory for AI Research, which was the intellectual progenitor of the work we did in our intelligent systems lab at Michigan State. This is an area rich in interesting applications for building computer models that support analysis o gait and the design of products.

    As I listened to Dennis's talk this morning, two connections to the world of computing came to mind. The first was to understand the remarkable amount of information technology involved in his company's work, including CAD, data interchange, and information storage and retrieval. As in most industries these days, computer science forms the foundation on which these folks do their work, and speed of communication and collaboration are a limiting factor.

    Second, Dennis's description of their development process sounded very much like a scrapheap challenge a lá the OOPSLA 2005 workshop of the same name. Creating a solution that works now for a specific individual, whose physical condition is unique, requires blending "space-age technology" with "stone-age technology". They put together whatever artifacts they have available to make what they need, and then they can step back and figure out how to increase their technical understanding for solving similar problems in the future.

    The Paul Graham article I discussed yesterday emphasized that students who think they might want to start their own companies should devote serious attention to finding potential partners, if only by surrounding themselves with as many bright, ambitious people as possible. But often just as important is considering potential partnerships with folks in industry. This is different than networking to build a potential client base, because the industrial folks are more partners in the development of a business. And these real companies are a powerful source of problems that need to be solved.

    My advice to students and anyone, really, is to be curious. If you are a CS major, pick up a minor or a second major that helps you develop expertise in another area -- and the ability to develop expertise in another area. Oh, and learn science and math! These are the fundamental tools you'll need to work in so many areas.

    Great talk. The sad thing is that none of our students heard it, and too few UNI faculty and staff are here as well. They missed out on a chance to be inspired by a guy in the trenches doing amazing work, and helping people as the real product of his company.


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

    October 12, 2006 4:51 PM

    Undergraduates and Start-Ups

    I enjoy following Paul Graham's writings about start-up companies and how to build one. One of my goals the last few years, and especially now as a department head, is to encourage our students to consider entrepreneurship as a career choice. Some students will be much better served, both intellectually and financially, by starting their own companies, and the resulting culture will benefit other students and our local and state business ecosystem.

    Graham's latest essay suggests that even undergraduate students might consider creating a start-up, and examines the trade-offs among undergrads, grad students, and experiences folks already in the working world. He has a lot more experience with start-ups than I, so I figure his suggestions are at least worth thinking about.

    Some of his advice is counterintuitive to most undergrads, especially to the undergrads in the more traditional Midwest. At one point, Graham tells students who may want to start their own companies that they probably should not take jobs at places where they will be treated well -- even Google.

    I realize this seems odd advice. If they make your life so good that you don't want to leave, why not work there? Because, in effect, you're probably getting a local maximum. You need a certain activation energy to start a startup. So an employer who's fairly pleasant to work for can lull you into staying indefinitely, even if it would be a net win for you to leave.

    It's hard for the typical 22-year-old to pass up a comfortable position at a top-notch but staid corporation. Why not enjoy your corporate work until you are ready to start your own company? You can make connections, build experience, learn some patterns and anti-patterns, and save up capital. The reason is that in short order you can create an incredible inertia against moving on -- not the least of which is the habit of receiving a comfortable paycheck each week. Going back to ramen noodles thrice daily is tough after you've had three squares paid for by your boss. I give similar advice to undergrads who say, "I plan to go to graduate school in a few years, after I work for a while." Some folks manage this, but it's harder than it looks to most students.

    I also give my students a piece of advice similar to another of Graham's suggestions:

    Most people look at a company like Apple and think, how could I ever make such a thing? Apple is an institution, and I'm just a person. But every institution was at one point just a handful of people in a room deciding to start something. Institutions are made up, and made up by people no different from you.

    The moral is: Don't be intimidated by a great company. Once it was just a few people mostly like us who had an idea and a willingness to make their idea work. I give similar advice about programs that intimidate my students, language interpreters and compilers. One of the morals of my programming languages and compilers courses is that each of these tools is "Just Another Program". Written by a knucklehead just like me. Learn some basic techniques, apply your knowledge of programming and data structures to the various sub-problems faced when building a language processor, and you can write one, too.

    This reference to professors raises another connection to Graham's advice, regarding how many students who want to create a start-up mistake the implementation of their idea as a commercial product with just a big class project:

    That leads to our second difference [between a start-up's product and a class project]: the way class projects are measured. Professors will tend to judge you by the distance between the starting point and where you are now. If someone has achieved a lot, they should get a good grade. But customers will judge you from the other direction: the distance remaining between where you are now and the features they need. The market doesn't give a shit how hard you worked. Users just want your software to do what they need, and you get a zero otherwise. That is one of the most distinctive differences between school and the real world: there is no reward for putting in a good effort. In fact, the whole concept of a "good effort" is a fake idea adults invented to encourage kids. It is not found in nature.

    The connection between effort, grade, and learning is not nearly as clean as most students think. Some courses require a lot of effort and require little learning; those are the courses that most of us hate. Sometimes one student has to exert much more effort than another to learn the concepts of a course, or to earn an equivalent grade. Every student starts in a different place, and courses exert different forces on different students. The key is to figure out which courses will best reward hard work -- preferably with maximum learning -- and then focus more of our attention there. Time and energy are scarce quantities, so we usually have to ration them.

    If an undergraduate knows that she wants to start her own company, she has a head start in making this sort of decision about where to exert their learning efforts:

    Another thing you can do [as an undergrad, to prepare to start your own company] is learn skills that will be useful to you in a startup. These may be different from the skills you'd learn to get a job. For example, thinking about getting a job will make you want to learn programming languages you think employers want, like Java and C++. Whereas if you start a startup, you get to pick the language, so you have to think about which will actually let you get the most done. If you use that test you might end up learning Ruby or Python instead.

    ... or Scheme! (These days, I think I'd go with Ruby.)

    As in anything else, having some idea about what you want from your future can help you make better decisions about waht you want to do now. I admire young people have a big dream even as undergrads; sometimes they create cool companies. They also make interesting students to have in class, because their goals have a groundedness to them. They ask interesting questions, and sometimes doze off after a long night trying something new out. And even with this lead in making choices, they usually get out into the world and end up thinking, "Boy, I wish I had paid more attention in [some course]." Life is usually more complicated than we expect, even when we try to think ahead.


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

    September 18, 2006 6:03 PM

    Professors Who Code

    Steve Yegge's entertaining fantasy on developing programmers contains a respectful but pointed critique of the relevance of a Ph.D. in computer science to contemporary software development, including:

    You hire a Ph.D., it's hit-or-miss. Some of them are brilliant. But then some subset of virtually every educated group is brilliant. The problem is that the notion of a Ph.D. has gradually been watered down for the last century. It used to mean something to be a Doctor of Philosophy: it meant you had materially advanced your discipline for everyone. Von Neumann, Nash, Turing -- people like that, with world-changing dissertations, ....

    ... These kids have to work hard for their Ph.D., and a lot of them never quite finish. But too often they finish without having written more than a few hundred lines of code in the past five years. Or they've over-specialized to the point where they now think Big-O is a tire company; they have no idea how computers or computation actually work anymore. They can tell you just about everything there is to know about SVM kernels and neural-net back propagation, or about photorealistic radiosity algorithms that make your apartment look fake by comparison. But if you want a website thrown together, or a scalable service written, or for that matter a graphics or machine-learning system, you're usually better off hiring a high-school kid, because the kid might actually know how to program. Some Ph.D.s can, but how many of them is it, really? From an industry perspective, an alarming number of them are no-ops.

    Ouch. I'm sure Steve is exaggerating for dramatic effect, but there is a kernel of truth in there. People who study for a Ph.D. in computer science are often optimizing on skills that are not central to the industrial experience of building software. Even those who work on software tend to focus on a narrow slice of some problem, which means not studying broadly in all of the elements of modern software development.

    So, if you want to apprentice with one person in an effort to learn the software industry, you can often find a better "master" than by selecting randomly among the run-of-the-mill CS professors at your university. But then, where will you connect with this person, and how will you convince him or her to carry you while you slog through learning the basics? Maybe when Wizard Schools are up and running everywhere, and the Ward Cunninghams and Ralph Johnsons of the world are their faculty, you'll have a shot. Until then, a CS education is still the most widely available and trustworthy path to mastery of software development available.

    You will, of course, have to take your destiny into your own hands by seeking opportunities to learn and master as many different skills as you can along the way. Steve Yegge reminds his readers of this all the time.

    In this regard, I was fortunate in my graduate studies to work on AI, in particular intelligent systems. You might not think highly of the work done by the many, many AI students of the 1980s. Paul Graham had this to say in a recent essay:

    In grad school I was still wasting time imitating the wrong things. There was then a fashionable type of program called an expert system, at the core of which was something called an inference engine. I looked at what these things did and thought "I could write that in a thousand lines of code." And yet eminent professors were writing books about them, and startups were selling them for a year's salary a copy. What an opportunity, I thought; these impressive things seem easy to me; I must be pretty sharp. Wrong. It was simply a fad.

    But whatever else you say, you have to admit that most of us AI weenies produced a lot of code. The AI and KBS research groups at most schools I knew sported the longest average time-to-graduate of all the CS areas, in large part because we had to write huge systems, including a lot of infrastructure that was needed in order to do the highly-specialized whatever we were doing. And many of us wrote our code in one of those "super-succinct 'folding languages'" developed by academics, like Lisp. I had the great good fortune of schlocking a non-trivial amount of code in both Lisp and Smalltalk. I should send my advisor a thank-you note, but at the time we felt the burden of all the code we had to produce to get to the place where we could test our cool ideas.

    I do agree with Yegge that progressive CS departments need to work on how better to prepare CS graduates and other students to participate in the development of software. But we also have to wrestle with the differences between computer science and software development, because we need to educate students in both areas. It's good to know that at least a few of the CS professors know how to build software. Not very many of us know when to set the fourth preference on the third tab of the latest .NET development wizard, but we do have some idea about what it's like to build a large software system and how students might develop the right set of skills to do the same.


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

    August 31, 2006 5:12 PM

    Names and Jargon in CS1

    As I've mentioned a few times in recent months that I am teaching our intro course this semester for the first time in a decade or so. After only two weeks, I have realized this: Teaching CS1 every so often is a very good idea for a computer science professor!

    With students who have no programming background, I cannot take anything for granted: values, types, variables, ... expressions, statements, functions/methods ... reference, binding ... so many fundamental concepts to build! In one sense, we have to build them from scratch, because students have no programming knowledge to which we can connect. But they do have a lot of knowledge of the world, and they know something about computers and files as users, and we can sometimes get leverage from this understanding. So far, I remain of the view that we can build the concepts in many different orders. The context in which students learn guides the ordering of concepts, by making some concepts relatively more or less "fundamental". The media computation approach of Guzdial and Ericson has been a refreshing change for me -- the idea of a method "happened" naturally quite early, as a group of operations that we have applied repeatedly from Dr. Java's interactions pane. Growing ideas and programs this way lets students learn bottom-up but see useful ideas as soon as they become useful.

    I've spent a lot of time so far talking about the many different kind of names that we use and define when thinking computationally. So much of what we do in computing is combining parts, abstracting from them an idea, and then giving the idea a name. We name values (constant), arbitrary or changing values (variable), kinds of values (type, class), processes (function, method)... Then we have arguments and parameters, which are special kinds of arbitrary values, and even files -- whose names are, in an important way, outside of our programs. I hope that my students are appreciating this Big Idea already.

    And then there is all of the jargon that we computer folks use. I have to assume that my students don't know what any of that jargon means, which means that (1) I can't use much, for fear of making the class sound like a sea of Babel, and (2) I have to define what I use. Today, for example, I found myself wanting to say "hard-coded", as such as a constant hard-coded into a method. I caught myself and tried to relate it to what we were doing, so that students would know what I meant, both now and later.

    I often speak with friends and colleagues who teach a lot of CS as trainers in industry. I wonder if they ever get a chance to teach a CS1 course or something like it. The experience is quite different for me from teaching even a new programming style to sophomores and juniors. There, I can take so much for granted, and focus on differences. But for my intro student the difference isn't between two somethings, but something and nothing.

    However, I also think that we have overglamorized how difficult it is to learn to program. I am not saying that learning to program is easy; it is tough, with ideas and abstractions that go beyond what many students encounter. But I think that sometimes lure ourselves into something of a Zeno's paradox: "This concept is so difficult to learn; let's break it down into parts..." Well, then that part is so difficult to learn that we break it down into parts. Do this recursively, ad infinitum, and soon we have made things more difficult than they really are -- and worse, we've made them incredibly boring and devoid of context. If we just work from a simple context, such as media computation, we can use the environment to guide us a bit, and when we reach a short leap, we make it, and trust our students to follow. Answer questions and provide support, but don't shy away from the idea.

    That's what I'm thinking this afternoon at least. Then again, it's only the end of our second week of classes!


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

    August 18, 2006 4:49 PM

    More on "Agile Teaching"

    If you've read many of my entries on agile software development, you know that I run the risk of being one of those guys who see agile principles everywhere I look in the world. I've certainly explored the relationship between agile approaches and my running. I've even seen agile truths a Bill Murray film.

    One way to do an analogy, and the people who use it, a disservice is take it too far, to go beyond where it adds value to where it misleads. But sometimes when we see something everywhere it's because it is everywhere, in some form. What's the pattern?

    I was again struck by the similarities between agile software development and teaching techniques while reading an article recently. Another department head in my college shared some of the papers she has been reading on how to improve the way we teach large, general-education courses. One of these papers is a product of the National Center for Academic Transformation, a project based on two ideas:

    • using scientific evidence from cognitive psychology and learning research to design instruction more effectively, and then
    • using information technology to implement instructional designs more efficiently and cost-effectively.
    One of the papers, Improving Quality and Reducing Cost: Designs for Effective Learning by Carol Twigg, motivated the ideas behind the project and described some of the hallmarks of courses redesigned according to them.

    The project currently focuses on the largest of courses in order to maximize its effect. According to Twigg, "just 25 courses generate about half of all student enrollments in community colleges and about a third of all enrollments in four-year institutions". This had never occurred to me but isn't too surprising, given that nearly all colleges students at every school take a common set of introductory courses in English, mathematics, science, and business. What did surprise me was the typical failure rates in these courses: 15% at research universities, 30-40% at comprehensive universities, and 50-60% at community colleges. Some of these failures are certainly the result of filtering out students who shouldn't be in college, but I have to think that a significant percentage of the failures are by people who have been poorly served by a lecture-only section of 100s of people.

    What does agile software development have to do with all this? In order to improve the quality of instruction (including the failure rates in these large and common courses) and reduce the cost of teaching them (in a climate of declining funding and rising expenses), this paper recommends that universities change the way they design and teach university courses -- in ways that echo how agile developers work, and using information technology to automate whatever automation can improve.

    One of the fundamental principles of this transformation is continuous assessment and feedback. Rather than testing students only with a midterm and a final, an instructor should keep in continuous touch with how students are comprehending the material. The traditional way to do this is to administer frequent quizzes, but that approach has as many minuses as plusses. Grading all those quizzes is a pain no sane instructor relishes, and you end up using a lot of class time taking quizzes.

    Technology can help here, if we think about automating continuous assessment and feedback. On-line quizzes can give students an opportunity to test their understanding frequently and receive feedback about what they know and don't know, and they can provide the instructor with feedback about both individuals and the group. Other technology can be more continuous yet, allowing instructors to quiz students "on the fly" and receive aggregated results immediately, a la Who Wants to be a Millionaire? Folks at my university have begun to use interactive feedback tools of this sort, but they haven't made their way into my department yet. Our most common immediate assessment-and-feedback tool is still the compiler.

    But the agile programmers -- and agile-thinking instructors -- among us know all about automating continuous assessment and feedback, and use more tools: IDEs that provide immediate compilation of code ... unit testing frameworks. Red bar, green bar! These tools help students know right where they are all the time, getting past some of the ticky-tack syntax issue that unnecessarily interfere with new students' progress. I think it's a huge win to let the IDE point out "you forgot a semicolon..." and "your code doesn't pass this test...".

    There is a risk in allowing students to develop a "do it 'til you get it right" mindset, but CS folks have already had to deal with this with the easy availability of compilers. Two years ago -- almost exactly! -- I wrote about this issue of multiple iterations and care for programs. Many professors still don't like that students can and do go through many compile iterations. Since that time, I've become even further convinced that students should do this, but learn how to do it right. People master skills by careful repetition, so we need to let them use repetition -- carefully, thoughtfully. In some ays, this seems like a statistical problem. To succeed by making random tries but never learning, they need to have time for a lot of tries. If they have that much time, then they have too little to do!

    The rest of the paper outlines other agile-sounding techniques: increased student interaction (pair programming), continuous support (the coach, and access to the working system), and sharing resources (collective ownership). But the key is feedback, and the use of automation to do this as cleanly and painlessly as possible.

    Ultimately, I just like the mentality these folks have about teaching. Twigg quotes a math prof involved with the project as saying, "Students learn math by doing math, not by listening to somebody talking about doing math." Of course! But you'd never know it by looking at most university courses.

    This sort of re-design requires a big change in how instructors behave, too, and that change is harder to effect than the one in students. Instructors are no longer primarily responsible for introducing basic material. (Isn't that what reading is for?) Instead, they need to be able to review what students have done and expand on it in real-time, extending what students do and leading them to new ideas and to integration of ideas. That's intimidating to most of us and so requires a whole new brain.


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

    August 12, 2006 2:21 PM

    Grades and Verticality

    The next book on my nightstand is Talking About Leaving: Why Undergraduates Leave the Sciences, by Elaine Seymour and Nancy Hewitt. The dean and department heads in my college have had an ongoing discussion of national trends in university enrollment in mathematics and the sciences, because all of our departments with the exception of biology have seen their number of majors drop in recent years. If we can understand the issue better, perhaps we can address it. Are students losing interest in the sciences in college? In high school? In grade school? Why? One of the common themes on this blog for the last year or so has been apparent declining interest in CS among students both at the university and in the K-12 system. At this point, all I know is that this is a complex problem with a lot of different components. Figuring out which components play the largest role, and which ones we as university faculty and as citizens can affect, is the challenge.

    My net acquaintance Chad Orzel, a physicist, recently commented on why they're leaving, drawing his inspiration from an Inside Higher Ed piece of the same name. That article offers four explanations for why students leave the physical sciences and engineering disciplines: lower GPAs, weed-out courses, large and impersonal sections, and "vertical curricula". The last of these refers to the fact that students in our disciplines often have to "slog" through a bunch of introductory skills courses before they are ready to do the intersting work of science.

    While Chad teaches at a small private college, my experience here at a mid-size public university seems to match with his. We don't have many large sections in computer science at UNI. For a couple of years, my department experimented with 100-person CS1 sections as a way to leverage faculty expertise in a particular language against our large enrollments. (Irony!) But for the most part our sections have always been 35 or less. I once taught a 53-person section of our third course (at that time, object-oriented programming), but that was an aberration. Our students generally have small sections with plenty of chance to work closely with the tenure-track faculty who teach them.

    We've never had a weed-out course, at least not intentionally. Many of our students take Calculus and may view that as a weeder, but my impression from talking to our students is that this is nothing like the brutal weed-out courses used in many programs to get enrollments down to a manageable size of sufficient quality. These days, the closest thing we have to a weed-out course is our current third course, Data Structures. It certainly acts as a gatekeeper, but it's mostly a matter of programming practice; students who apply themselves to the expectations of the instructor ought to be able to succeed.

    The other two issues are problems for us. The average GPA of a computer science student is almost surely well below the university average. I haven't seen a list of average GPAs sorted by department in many years, but the last few times I did CS and economics seemed to be jostling for the bottom. These are not disciplines that attract lots and lots of weak students, so grading practices in the departments must play a big role. As the Inside Higher Ed article points out, This culture of grading is common in the natural sciences and the more quantitative social sciences at most universities. I don't doubt that many students are dissuaded from pursuing a CS major by even a B in an intro course. Heck, they get As in their other courses, so maybe they are better suited for those majors? And even the ones who realize that this is an illogical deduction may figure that their lives will simply be easier with a different major.

    I won't speak much of the other problem area for us, because I've written about it a lot recently. I've never used the word "vertical" to describe our problem of boring intro courses that hide or kill the joy of doing computing before students ever get to see it, but I've certainly written about the issue. Any student who graduates high school with the ability to read is ready for a major in history or communication; the same student probably needs to learn a programming language, learn how to write code, and figure out a lot of new terminology before being ready to "go deep" in CS. I think we can do better, but figuring out how is a challenge.

    I must point out, though, that the sciences are not alone in the problem of a vertical curriculum. As an undergraduate, I double-majored in CS and accounting. When I switched from architecture to CS, I knew that CS was what I wanted to do, but my parents encouraged me to take a "practical" second major as insurance. I actually liked accounting just fine, but only because I saw past all of the bookkeeping. It wasn't until I got to managerial accounting as a junior and auditing as a senior that I got to the intellectually interesting part of accounting, how one models an organization in terms of its financial system in order to understand how to make it stronger. Before that came two years of what was, to me, rather dull bookkeeping -- learning the "basics" so that we could get to the professional activities. I often tell students today that accounting is more interesting than it probably seems for the first one, two, or three years.

    Computer science may not have moved much faster back then. I took a one-quarter CS 1 to learn how to program (in Fortran), a one-quarter data structures course, and a couple of courses in assembly language, job control language, and systems programming, but within three or four quarters I was taking courses in upper-division content such as databases, operating systems, and programming languages -- all of which seemed like the Real Thing.

    One final note. I actually read the articles mentioned at the beginning of this essay after following a link from another piece by Chad, called Science Is Not a Path to Riches. In it, Chad says:

    A career in research science is not a path to riches, or even stable employment. Anyone who thinks so is sadly deluded, and if sure promotion and a fat paycheck are your primary goal (and you're good at math), you should become an actuary or an accountant or something in that vein. A career in research science can be very rewarding, but the rewards are not necessarily financial (though I hasten to add, I'm not making a bad living, either).

    This is one place where we differ from physicists and chemists. By and large, CS graduates do get good jobs. Even in times of economic downturn, most of our grads do pretty well finding and keeping jobs that pay above average for where they live. Our department is willing to advertise this when we can. We don't want interested kids to turn away because they think they can't get a job, because all the good jobs are going to India.

    Even still, I am reluctant to over-emphasize the prospect of financial reward. For one thing, as the mutual fund companies all have to tell us, "past performance is no guarantee of future results". But more importantly, intrinsic interest matters a lot, too, perhaps more so than extrinsic financial reward, when it comes to finding a major and career path that works. I'd also like to attract kids because CS is fun, exciting, and worth doing. That's where the real problem of 'verticality' comes in. We don't want kids who might be interested to turn away because the discipline looks like a boring grind.

    I hope to learn more about this systemic problem from the empirical data presented in Talking About Leaving, and use that to figure out how we can do better.


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

    August 11, 2006 8:23 AM

    An Unsuccessful Curriculum Proposal

    Now that the issue has been resolved, I can finally write on a topic I mentioned three weeks ago, my department's proposal to create a new major in Software Engineering. This is one of those persistent "interruptions" this summer that really was an important task in its own right. It also reminds us all that academic politics are a non-trivial exercise.

    A couple of years ago, the faculty in my department decided to propose three new majors. One, bioinformatics, targeted an area of growing importance in which computing is an essential component. Graduate programs in bioinformatics were becoming common at this time, but few or no undergraduate programs existed. We figured that this major would attract a new audience of potential students and capitalize on the strong math and biology departments here. The other two proposals were extensions of the standard B.S. in Computer Science program we already offered: Software Engineering, and Networking and System Administration. These proposals targeted particular professional areas that our students pursue within our existing majors, giving them a little extra heft and their own identity. We figured that these majors would allow current CS students to choose a major that more directly matched their professional careers and hoped that they would attract students interested in these areas who might otherwise not attend our university.

    Such "targeted majors" are becoming more common throughout the country, and we hoped to be in the vanguard. Personally, I'm not a big fan of "superset majors" like Software Engineering and Networking, because I think even our most professionally-oriented students are best served with a broad CS major that prepares them for a diverse and dynamic discipline. But I do understand their appeal to students and thus their utility as marketing tools. Add to this reports such as Iowa's Information Technology Strategic Roadmap, which recommends focused majors as tools for developing the state's base of IT workers, and such majors become even more attractive to the university. At a time when our discipline is changing, such majors represent a reasonable effort to broaden and focus our reach at the same time.

    In order to create a new major at one of Iowa's three public universities, you must have it approved by the system-wide Board of Regents. Before a proposal reaches the Board level, though, it first must receive approval from the provosts at the three institutions. This is a reasonable mechanism which generally ensures that all of the universities know what the others are doing, helps identify opportunities for collaboration, and prevents unnecessary duplication in programs.

    Our bioinformatics and NaSA proposals were approved in the initial proposal cycle, but software engineering was not. One of our sister institutions raised objections to all three proposals, but the other gave us its blessing. As part of a compromise to overcome the objections, our administration withdrew the Software Engineering proposal from the table. This succeeded because, while the objecting school would have preferred that we not offer any of the new majors, its greatest objection was to the Software Engineering proposal. This objection ultimately came down to our use of the word 'engineering' in the title of a degree program. The other schools have Colleges of Engineering, but we do not.

    Engineers take use of the word 'engineering' quite seriously as a matter of professional honor. To them, engineering means something specific, and engineering education requires a specific set of courses in mathematics and the physical sciences, as well as specific experiences rooted in how professional engineers craft their trade. My university does not offer a traditional engineering program, so our engineering colleagues do not consider us capable of offering an engineering major.

    So we passed on our Software Engineering proposal and put our energies into launching the other two new majors. They've now been on the books for a year and have begun to attract majors. We've also experimented with professional marketing techniques to introducing bioinformatics to our target audiences.

    By the time I became department head, we had a new dean and a new provost, and our faculty really wanted to re-propose the Software Engineering major. The faculty did not feel that the original proposal had been dismissed on its merits, but rather for political reasons, and they wanted the chance to make their case that we be allowed to offer this new major, which so closely aligns with the professional goals of many of our students.

    So we set out to educate our new administration on the discipline and why our university should be offering degrees in software engineering. Once they were convinced, we took our case back to the council of provosts. Not too surprisingly, we encountered the same objection.

    Actually, we encountered several objections. Since the time of our initial proposal, the objecting school had proposed its own Software Engineering degree program. So now there were concerns about duplication of effort and resources. Those of you on university faculties surely know that duplication among state schools is a big issue these days. State funding isn't as plentiful as it used to be, and so unnecessary duplication is viewed as an unacceptable financial luxury.

    Another objection involved the fact that we did not intend to seek accreditation of our program by ABET, the standard accrediting agency for engineering programs. As a matter of professional standards, nearly all traditional engineering programs are accredited by ABET. Software engineering programs are a relatively recent phenomenon, as is their accreditation. Programs started within colleges of engineering do tend to seek accreditation, but not all do. A considerable number of undergraduate software engineering programs -- about a quarter of the thirty programs currently being offered in the U.S. -- lie outside of an engineering college and are much less likely ever to seek accreditation.

    This might be a concern for the established engineering disciplines, but I think it is less of an issue for software engineering. I'm not sure we know how to "engineer" large software all that reliably yet, and I'm not sure that we have a good sense of what all software engineers should know or be able to do. Projects such as SWEBOK are valuable efforts to catalog our current understanding, but what we really need is many more years building big systems and examining our practices along the way.

    This brings us back to the semantic issue that lies at the heart of the objections to our program proposal. Our engineering colleagues consider software engineering to be an engineering discipline like mechanical or electrical or civil engineering, and as such they think it should be treated like the traditional engineering programs. Whatever the professional assessment of engineering colleges regarding the use of the word "engineering", the term "software engineering" is widely used throughout the U.S. and the world in a broad sense, to describe the disciplined construction of software systems. Courses in software engineering are offered by many different academic institutions, including the majority of Computer Science departments these days. Graduates of computer science and information systems programs move immediately into positions with the title "software engineer" in many different kinds of companies. For our students, these employers ranges from traditional engineering companies to financial services companies such as insurance companies and banks. Many small, independent software developers consider themselves to be software engineers, though they would never consider becoming a licensed professional engineer. Standard use of the term "software engineering" does not indicate "engineering" in the sense understood by the engineering profession.

    Perhaps it should. Our colleges of engineering would prefer to define the term prescriptively, setting standards and ensuring that anyone who bears the title of engineer meet a set of common standards first. This is a noble aspiration. But my definition of the term is descriptive, in the sense of describing how it is used by people out in the world. In this descriptive sense, I think it is perfectly reasonable for my university to offer a Software Engineering degree.

    Alas, I am not the one to make this decision. Our sister institutions persisted in their objections to our proposal, and so again it failed. Had we changed the name of our program to Software Development or almost anything else without the word 'engineering' in it, we would probably have succeeded in having our program approved. Our faculty decided that to change the name of our program to something non-standard would defeat the purpose of offering a specialized degree in the discipline; it wouldn't match up with the expectations of students or the companies that hire them. Besides, the non-standard name feels distinctly sub-standard, as if we aren't capable of offering a degree in the discipline that folks have come to regard as standard in industry.

    Sadly, I fear that there may have been an element of this thinking in our sister institution's objection to our proposal. They think us worthy of offering an "applied computer science" program in something called software development, but not worthy of awarding degrees in Software Engineering.

    I work at a so-called teaching university. While most of our faculty is engaged in research and other scholarly activity, basic research is not our mission; producing well-educated citizens is. A computer science program at a school such as mine blends a solid core of empirical CS with what amounts to professional education, not all that different from the pre-professional programs we offer students interested in pursuing law degrees and medical degrees. For most of our CS students, computer science is a professional degree, and software engineering is one of their professions of choice. One of our goals is to produce broadly educated practitioners in a discipline that changes rapidly, while at the same time changing the world in which the practitioners practice.

    Ultimately, I think that our position on who should be teaching software engineering will be proven right by history. While I am not a big fan of the metaphor, software engineering as a discipline is much bigger than colleges of engineering conceive it, and more and more schools will teach it. In the meantime, we will continue on with what we have -- a B.S. program in Computer Science, with a Software Engineering emphasis -- and prepare students to enter the world ready to develop software, including the largest of systems, whatever that activity may be like in the future.

    I sit hear now wondering what software engineering programs in colleges of engineering and think about agile approaches to software development. Maybe we are lucky not to be constrained by the straightjacket of expectations that accompany the programs in established engineering disciplines. We are still learning how to build software, and we can fold our learning into our courses and curricula much faster when we don't have to worry about a set of restrictions based in other engineering disciplines.

    Anyway, for those of you who think that "office politics" in the "real world" make life worse than it is in the ivory tower, this little story only scratches the surface of what university politics are like. That's a whole other story...


    Posted by Eugene Wallingford | Permalink | Categories: Managing and Leading, Software Development

    August 01, 2006 7:16 PM

    Design as Choice

    Last week, I quoted Bob Martin on the interplay between design and building:

    You always have to design something before you build it. The question is: "How much do I have to design before I build?" ... the act of building is *part* of the act of design....

    To many people, this sense of design is heresy. They prefer a more formal definition, one that makes clear a distinction between between design and implementation, and analysis and design. Even in a day where iterative models of software development have replaced the waterfall model in the minds of even the most traditional software engineers, many people still think of the phases of development as very different.

    Agile software developers seek to iterate more quickly through the phases of software development, in large part because of what Martin reminds us: we learn too much about our design from writing code to wait very long to begin writing code. Likewise, we learn too much from our design and coding about how well we understand our problem to wait very long to begin designing and writing code.

    So, what is the best definition of design for us to use in our work, and with our students and new hires? Folks who see the phases of software development as Major Events to be seen as separate activities are most likely to give Major Definitions to the phases. But I've learned a lot about design from folks who have more pragmatic takes on software development.

    Sometime last year, the members of a mailing list I'm on discussed the definition of design. Jim Coplien and Grady Booch gave very thorough definitions of design, both the verb (the act of designing) and the noun (the artifact produced). Both of their definitions incorporated the idea of a system and its behavior, related to the forces that exist in the system's intended environment. The thing I liked best about Booch's definition was how it managed to account for the scientific side of design, where empiricism and experiment help us to make optimal decisions in a large search space, as well as the artistic side, where science leaves enough degrees of freedom to enable clever and elegant decisions.

    Whatever else design is, it is about the choices we make while building things. Some of the features of a system are required by the customer, and others are driven by the technologies that we use, including the programming language. The rest of the system is determined by the developer. This is how James Noble characterized design in our e-mail discussion: the decisions we make that determine the rest of the system.

    By the way, Noble's definition reminds us just how important it is not to use an overly restrictive programming language when we build systems. Such a language makes too many decisions for us upfront, without regard the problem we are solving or the environment in which the system will live. Choosing such a language surrenders too much freedom, too much possibility, too soon.

    Once we get to the point of seeing design as being about choices, and without any predisposition to create a complex definition in order to distinguish design in some formal way, we can get to my all-time favorite one-line definition of design. This definition is courtesy of Ward Cunningham, whose gift for simplicity I have extolled before:

    Design is your choices that stick.

    This brings us back to the fundamental truth in the agile approach captured by Robert Martin in the passage above: Not all of our choices will stick, and we need to learn which will and which won't as quickly as possible, from whatever sources we have available. And that includes the program itself.


    Posted by Eugene Wallingford | Permalink | Categories: Software Development

    July 27, 2006 1:31 PM

    "July 27 at 2:00 PM"

    That was my standard answer to a particular family of questions for many years. The prototypical question in this family was, "Do you think you'll ever want to be a department head?" And I always said, "July 27 at 2:00 PM".

    If you are a faculty member or even a graduate student, you probably know just what I meant. Summer is a great time to be a faculty member. We get to read, write code, play with new ideas -- all without having to worry about preparing for and meeting classes, attending department meetings, or otherwise doing much with the day-to-day business of the university. Even better, we can read, write, and play most anywhere we want, most anytime we want. We can become absorbed in a program and work all day, and never have to worry about a meeting or a class interrupting the flow. We can work from home or from the road, but we don't have to work at our offices unless we want to. No one expects us to be there much.

    Department heads, though, are administrators. The daily business of the university goes on, and the heads have to keep tabs on it. There are salary letters to be written, budgets to be closed, memos to write for the dean and provost, and inquiries to be answered. The university pays their salary during the summer, and the university expects a return on its investment.

    So, there we are, 2:00 PM on a beautiful Thursday, July 27th. As a faculty member, I could be almost anywhere, doing almost anything, learning something new. As a department head, I would be in the office, dressed well enough to meet the public if necessary, "working".

    "July 27 at 2:00 PM" meant "I don't think so, and here's why...".

    The great irony is that I am now finishing up my first year as department head now, and it is nearly 2:00 PM on Thursday, July 27. It's overcast outside, not sunny, and frightfully muggy. Where am I? In my home study. What am I doing? Reading from the stack of papers that has built up over the last few months, and writing a quick entry for this blog. Not much different than any other summer in the past 15 years.

    However, I stand by metaphorical answer. All other things being equal, summer life as a faculty member is freer and open to more possibilities than summer life as a department head. It requires some adjustment.

    My reading today has been from an old-fashioned pile of stuff, the papers and journal articles that I run into during busy days and set aside for later. I don't know about you, but my eyes are always bigger than my stomach when it comes to the list of things I want to read. So I print them out and wait for a free moment. Eventually the pile of papers exceeds any realistic amount of time I have to read and the amount of space I have to store them. Today, I made a few free moments to do triage, tossing papers that I know I'll never get to and, every so often, stopping to read something that sounds good right now. A very few papers earn a spot in the new, streamlined pile of stuff, in an almost certainly fantastic hope that some day I'll get to them.

    Here are two passages I read today that made the effort worthwhile. First, a quote from Uncle Bob Martin, from a 2004 message to the extreme programming mailing list, in the thread "Designing before doing":

    >  "But how can you do anything without designing it first?!" ...

    You can't. You always have to design something before you build it.

    The question is: "How much do I have to design before I build?"

    The answer is: "Just enough so that what I build gives me better insight into the design of the next step."

    Seen this way, the act of building is *part* of the act of design, and the original question inverts itself: "How can you design something without verifying your design decisions by implementing them?"

    Well said. Thank you, Uncle Bob.

    Finally, a bit of humor from Eric Raymond's classic FAQ, How to Become a Hacker:

    Q:
    I'm having problems with my Windows software. Will you help me?

    A:

    Yes. Go to a DOS prompt and type "format c:". Any problems you are experiencing will cease within a few minutes.

    Enjoy your July 27!


    Posted by Eugene Wallingford | Permalink | Categories: Managing and Leading, Software Development

    July 26, 2006 2:27 PM

    A Classic David Gries Article on Intro Courses

    Summer is a great time to read old papers, though this summer has been too light on free reading time for my tastes. This morning, I read David Gries's 1974 SIGCSE paper What Should We Teach in an Introductory Programming Course?, which came up in a SIGCSE mailing list discussion earlier this year. Gries has long been involved in the effort to improve computer science instruction, from at least his 1973 PL/I-based intro text with Conway, An Introduction to Programming up to his recent multimedia effort Program Live!, with his son, Paul. In part because his work tends to be more formalist than my own, I usually learn a lot from his writing.

    This paper focuses on two of what Gries thinks are the three essential aspects of an intro course: how to solve problems and how to describe solutions algorithmically. His discussion of general problem solving was the reason the paper came up in the SIGCSE discussion, which considered how best to teach students "general problem-solving skills". Gries notes that in disciplines such as philosophy one studies problem-solving methods as philosophical stances, but not as processes to try in practice, and that in subjects such as mathematics one learns how to solve specific classes of problems by dint of repetition. By exposing students to several classes of problem, teachers hope that they generalize their learning into higher-order skills. This is true in many disciplines.

    But we in computer science face a more challenging problem. We strive to teach our students how to write programs that solve any sort of problem, whether from business or science or education. In order to program well across all the disciplines, our students must learn more general problem-solving skills.

    That said, I do not think that we can teach general problem-solving skills in our intro course, because I do not think the brain works that way. A lot of evidence from cognitive psychology shows that humans learn and tend to operate in specific contexts, and expertise transfers across boundaries only with great attention and effort. The the real question is not how we can teach general problem-solving skills in our intro course, but rather how can we help students develop general problem-solving skills over the course of our curriculum. My current belief is that we should teach programming in context, while opportunistically pointing out the patterns that students see and will see again later. Pick a context that students care about, so that they will have plenty of their own motivation to succeed. Then do it again, and again. By making explicit the more general patterns that students see, I think that we can do better than most CS and math curricula currently do. We would not be teaching general problem-solving skills in any course so much as creating an environment in which students can maximize their likelihood of "getting it". Our courses should not be weed-out courses, because I think most students can get it -- and we need them to, whether as CS majors or as non-majors prepared to participate in a technological society.

    When Gries looked at what people were teaching in intro CS courses back then, he found them doing what many of our courses do now: describing a set of tools available in a programming language, showing students a few examples, and then sending them off to write programs. Not much different than our math brethren teaching differentiation or integration. Gries exposes the folly in this approach with a little analogy:

    Suppose you attend a course in cabinet making. The instructor briefly shows you a saw, a plane, a hammer, and a few other tools,letting you use each one for a few minutes. He next shows you a beautifully-finished cabinet. Finally, he tells you to design and build your own cabinet and bring him the finished product in a few weeks.

    You would think he was crazy!

    (For some reason, this passage reminded me of a witty student evaluation that Rich Pattis shared in his SIGCSE keynote address.)

    Gries offers a few general principles from the likes of Descartes, Polya, and Dijkstra and suggests that we might teach them to students, that they might use the principles to help themselves organize their thoughts in the midst of writing a complex program. I suspect that their greatest value is in helping instructors organize their thoughts and keep the ultimate goal of the course in mind. For example, while reading this section, I was struck by Polya's fourth phase of solving problems: "Look back". We instructors must remember to give our students both the opportunity to look back at what they've done and think about their process and product, and the time to consolidate their learning. So often, we are driven by the need to cover more, more, more material, and the result is a treadmill from which students fall at the end of the course, exhausted and not quite sure what all just happened.

    Gries then offers a language for describing algorithms, very much in sync with the Structured Programming movement of the 1970s. My primary reaction to this discussion was "where are the higher-level patterns?" If all we teach students are basic statements, procedure definitions and calls, and control structures, we are operating only barely above the level of the programming language -- and thus leaving students to discover on their own fundamental patterns like Guarded Linear Search.

    What language should we teach in the intro course? Gries attacks this question with gusto. As I've written before, language sniping is a guilty pleasure of mine, and Gries's comments are delightful. Indeed, this whole paper is written in a saucy style not often seen in academic papers, then and especially now. I wonder if most SIGCSE referees would let such style pass these days?

    First, Gries reminds us that in an intro the programming language is only a vehicle for teaching the ideas we think are important. It should be as close as possible to the way we want students to think about programs, but also "simple, elegant, and modular, so that features and concepts not yet taught won't get in the way." (As a smug language weenie, I am already thinking Smalltalk or Scheme...) But we usually teach the wrong language:

    The language taught is often influenced by people outside the computer science profession, even though their opinions are not educated enough to deserve recognition.

    At the time he wrote the paper, Gries would like to have taught Pascal, BLISS, or a variant of Algol, but found that most departments taught Fortran, BASIC, or PL/I. Gries minces no words. On Fortran:

    Fortran is out of date and shouldn't be used unless there is absolutely nothing else available. If this is the case, use it under protest and constantly bombard the manufacturers or other authorities with complaints, suggesting the make available a more contemporary.

    I learned Fortran in my CS 1 course back in 1983!

    On Basic:

    [It] should never have come into existence. When it was contemplated, its designers should have done their research to see what programming and programming languages are all about before plunging in.

    I learned Basic as my first programming language in high school, in 1980!

    But then Gries expresses one of the tenets of his approach that I disagree with:

    I have doubts about teaching students to think "on-line"; algorithms should be designed and written slowly and quietly at one's desk. Only when assured of correctness is it time to go to the computer and test the algorithm on-line.

    First, notice the older sense of "on-line". And then ask yourself: Is this how you program, or how you want to program? I know I'm not smart enough to get any but the most trivial programs correct without testing them on-line.

    Of the choices realistically available, Gries decided that PL/I was the best alternative and so wrote his text with with Conway. I used the 1979 version of this text as the PL/I reference in my data structures course back in 1983. (It was the language companion to the language-independent Standish text I so loved.)

    Even though Gries grudgingly adopted PL/I, he wasn't happy:

    What's wrong with PL/I? Its syntax is enough to offend anyone who has studied English grammar; its data structure facilities ... could have been less clumsy ...; it is not modular ...; its astonishment factor is much too high (e.g., what is 25 + 1/3 ?); ... and so on.

    But with the right subset of the language, Gries felt he could teach structured programming effectively. That is just the sort of compromise that C++ advocates made in the 1990s. I willingly accepted C++ as a CS 1 language myself, though it didn't take long for me to realize that this was a mistake. By comparison, PL/I was a relatively nice language for novices.

    The last section of Gries's paper turns to the topic of program documentation. His central tenet will sound familiar to agile programmers of the new century:

    Program documentation should be written while the program is being written, if not before, and should be used by the programmer in proving correctness and in checking his program out.

    This is a fine argument for test-driven development! This is a common theme among formalist computer scientists, and one I've written about with regard to Edsger Dijkstra. The place where the agile folks diverge from folks like Gries and Dijkstra is in their strong conviction that we should use code -- executable tests -- to document the intended behavior of the system. If the documentation is so valuable, why not write it in a form that supports automated application and continuous feedback? Sitting quietly at one's desk and writing an outline of the intended algorithm by candlelight seems not only quaint but also sub-optimal.

    The outline form that Gries recommends is certainly more palatable than other alternatives, such as flowcharts. I think that the modern rendition of this approach is Matthias Felleisen's design recipe approach, described most completely in How to Design Programs. I have great respect for this work and am always looking for ways to use its ideas to improve how I teach.

    Gries concludes his paper with good advice on "practicing what you teach" for any instructor:

    The students will easily sense whether you believe in what you tell them, and whether you yourself practice what you teach.

    He wrote this at a time when many CS instructors needed to be retrained to teach the new orthodoxy of structured programming. It has been equally true over the last ten years or so, with the move to object-oriented programming and then agile approaches. One of the reasons I dislike textbooks these days is that too often I get the sense that the authors don't really believe what they are saying or, if they do, that the belief is more a skin they've put on than a deep grokking of the ideas. Gries advises ways in which to deepen one's understand, including the surprisingly surprising "write several programs, both large and small, using the tools and techniques advocated". Why should this be surprising to anyone? I don't know, but I wonder how many folks who now teach an OO intro course have ever written and lived inside a large object-oriented program.

    The end of this paper supports a claim I made about academic conservatism a couple of years ago, and brings us back to Dijkstra again. First he expresses hope:

    You would think that the University, where one searches for truth and knowledge, would be the place for innovative thinking, for people are tuned to new and better ideas.

    ... and then he quotes Dan McCracken, who had surveyed academics about their intro courses:

          "Nobody would claim that Fortran is ideal for anything, from teachability, to understandability of finished programs, to extensibility. Yet it is being used by a whopping 70% of the students covered by the survey, and the consensus among the university people is that nothing is going to change much anytime soon."

    Does this sound like educators who are committed to teaching concepts, to teaching people what they need to know to prepare for the future?

    As noted above, my alma mater was still teaching Fortran in CS 1 into the 1980s. Gries is hard on his colleagues, as I have been at times, but the truth is that changing how one programs and teaches is hard to do. And he and I have been guilty of making PL/I-like compromises, too, as we try to introduce our own ideas. The lesson here is not one of blame but one of continually reminding ourselves of what matters and trying to make those things happen in our courses.

    Reading this paper was a nice diversion from the other duties I've been facing lately, and a nice way to start preparing more for my fall CS 1 course.


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

    July 14, 2006 5:29 PM

    Growing a Tech Industry Instead of Corn

    One of the enjoyable outreach activities I've been involved with as department head this year has been the state of Iowa's Information Technology Council. A few years back, the Iowa Department of Economic Development commissioned the Battelle corporation to study the prospects for growing the state's economy in the 21st century. They focused on three areas: bioscience, advanced manufacturing, and information technology. The first probably sounds reasonable to most people, given Iowa's reputation as an agriculture state, but what of the other two? It turns out that Iowa is much more of a manufacturing state than many people realize. Part of this relates back to agriculture. While John Deere is headquartered in Moline, Illinois, most of its factories are in Iowa. We also have manufacturers such as Rockwell Collins and Maytag (though that company has been purchased by Whirlpool and will close most or all of its Iowa locations soon).

    But information technology? Des Moines is home to several major financial services companies or their regional centers, such as Principal Financial Group and Wells Fargo. Cedar Rapids has a few such firms as well, as well as other companies with a computing focus such as NCR Pearson and ACT.

    IDED created the IT Council to guide the state in implementing the Information Technology Strategic Roadmap developed by Battelle as a result of its studies. (You can see the report at this IDED web page.) The council consists of representatives from most of Iowa's big IT firms and many of the medium-sized and small IT firms that have grown up throughout the state. Each of the three state universities has a representative on the council, as does the community college system and the consortium of Iowa's many, many private colleges and universities. I am UNI's representative.

    The council has been meeting for only one year, and we have spent most of our time really understanding the report and mapping out some ideas to act on in the coming year. One of the big issues is, of course, how Iowa can encourage IT professionals to make the state their home, to work at existing companies and to create innovative start-ups that will fuel economic growth in the sector. Another part of the challenge is to encourage Iowa students to study computer science, math, and other science and engineering disciplines -- and then to stay in Iowa, rather than taking attractive job offers from the Twin Cities, Chicago, Kansas City, and many other places with already-burgeoning IT sectors.

    To hear Paul Graham tell it, we are running a fool's errand. Iowa doesn't seem to be a place where nerds and the exceedingly rich want to live. Indeed, Iowa is one of those red states that he dismisses out of hand:

    Conversely, a town that gets praised for being "solid" or representing "traditional values" may be a fine place to live, but it's never going to succeed as a startup hub. The 2004 presidential election ... conveniently supplied us with a county-by-county map of such places. [6]

    Actually, as I look at this map, Iowa is much more people than red, so maybe we have a chance! I do think that a resourceful people that is willing to look forward can guide its destiny. And the homes of our three state universities -- Iowa City, Ames, and Cedar Falls -- bear the hallmark of most university towns: attracting and accepting more odd ideas than the surrounding environment tends to accept. But Iowans are definitely stolid Midwestern US stock, and it's not a state with grand variation in geography or history or culture. We have to bank on solidity as a strength and hope that some nerds might like to raise their families in a place with nice bike trails and parks, a place where you can let your kids play in the neighborhood with fearing the worst.

    We also don't have a truly great university, certainly not of the caliber Graham expects. Iowa and Iowa State are solid universities, with very strong programs in some areas. UNI is routinely praised for its efficiency and for its ability to deliver a solid education to its students. (Solid -- there's that word again!) But none of the schools has a top-ten CS program, and UNI has not historically been a center of research.

    I've sometimes wondered why Urbana-Champaign in Illinois hasn't developed a higher-profile tech center. UIUC has a top-notch CS program and produces a lot of Ph.D., M.S., and B.S. graduates every year. Eric Sink has blogged for a few years about the joys of starting an independent software company amid the farmland of eastern Illinois. But then there is that solid, traditional-values, boring reputation to overcome. Chicago is only a few hours' drive away, but Chicago just isn't a place nerds want to be near.

    So Iowa is fighting an uphill battle, at least by most people's reckoning. I think that's okay, because I think the battle is still winnable -- perhaps not on the level of the original Silicon Valley but at least on the scale needed to invigorate Iowa's economy. And while reputation can be an obstacle, it also means that competitors may not be paying enough attention. The first step is to produce more tech-savvy graduates, especially ones with an entrepreneurial bent, and then convince them to stay home. Those are steps we can take.

    One thing that has surprised me about my work with the IT Council is that Iowa is much better off on another of Graham's measures than I ever realized, or than most people in this state know. We have a fair amount of venture capital and angel funding waiting for the right projects to fund. This is a mixture of old money derived from stodgy old companies like Deere and new money from the 1990s. We need to find a way to connect this money to entrepreneurs who are ready to launch start-ups, and to educate folks with commercializable ideas on how to make their ideas attractive to the folks with the money.

    Here at UNI, we are blessed to have an existence proof that it is possible to grow a tech start-up right here in my own backyard: TEAM Technologies, which among its many endeavors operates the premier data center in the middle part of the USA. A boring, solid location with few people, little crime, and no coastal weather turns out to be a good thing when you want to store and serve data safely! TEAM is headed up by a UNI alumnus -- another great strength for our department as we look for ways to expand our role in the economic development of the state.


    Posted by Eugene Wallingford | Permalink | Categories: Computing, General, Managing and Leading, Software Development

    June 29, 2006 11:47 AM

    Buried Treasures

    I finally got around to reading Glenn Vanderburg's Buried Treasure. The theme of his article is "our present is our past, and there's more past in our future". Among his conclusions, Glenn offers some wisdom about programming languages and software education that we all should keep in mind:

    What I've concluded is that you can't keep a weak team out of trouble by limiting the power of their tools. The way forward is not figuring out how to achieve acceptable results with weak teams; rather, it's understanding how to build strong teams and how to train programmers to be part of such teams.

    Let's stop telling ourselves that potential software developers can't learn to use powerful tools and instead work to figure out how to help them learn. Besides, there is a lot more fun in using powerful tools.

    Glenn closes his article with a nascent thought of his, an example of how knowing the breadth of our discipline and its history might help a programmer solve a thorny problem. His current thorny problem involves database migration in Rails, and how that interacts with version control. We usually think of version control as tracking static snapshots of a system, but a database migration subsystem is itself a tracking of snapshots of an evolving database schema -- so your version control system ends up tracking snapshots of what is in effect a little version control system! Glenn figures that maybe he can learn something about solving this problem from Smalltalkers, who deal with this sort of this thing all the time -- because their programs are themselves persistent objects in an evolving image. If he didn't know anything about Smalltalk or the history of programming languages, he might have missed a useful connection.

    Speaking of Smalltalk, veteran Smalltalker Blaine Buxton wrote recently on a theme you've seen here: better examples. All I can say is what Blaine himself might say, Rock on, Blaine! I think I've found a textbook for my CS 1 course this fall that will help my students see lots of more interesting examples than "Hello, world!" and Fibonacci numbers.

    That said, my Inner Geek thoroughly enjoyed a little Scheme programming episode motivated by one of the comments on this article, which taught me about a cool feature of Fibonacci numbers:

    Fib(2k) = Fib(k) * (Fib(k+1) + Fib(k-1))

    This property lends itself to computing Fib very efficiently using binary decomposition and memoizing (caching perviously computed values). Great fun to watch an interminably slow function become a brisk sprinter!

    As the commenter writes, simple problems often hide gems of this sort. The example is still artificial, but it gives us a cool way to learn some neat ideas. When used tactically and sparingly, toy examples open interesting doors.


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

    June 28, 2006 4:22 PM

    One Reason I Like Agile Methods

    Short answer: Because sometimes I am too cocky for my own good.

    If you read the recent entry on my latest half marathon, you may have noticed that my mile 3 time stands out as slower than the rest. What happened? After running two comfortable miles at exactly 7:32, about a half minute faster than planned, I started daydreaming about what a great race I would soon have run. "Let's see, that's 91... plus six-and-a half, which is... Wow!" While patting myself on the back in advance, I forgot to keep running. Too cocky.

    Last summer, when I took on the responsibilities of department head, I managed to convince myself that I was the best person for the job. Maybe even the only person. With this attitude, it is all too easy to fall into habits of thought and action where I forget that I have to do the hard work of the job. Why aren't things coming more easily? Too cocky.

    So it is with programming. It's quite easy to attack a problem before we fully understand our customer's needs, to start pumping out code before we know where we are going. Get cocky, and pretty soon the problem and the program step up to humble me. Unfortunately, by then, I too often have a big mess on my hands.

    I work better when I'm a little nervous, when I'm a bit unsure of whether I can do what I'm trying to do. Maybe that's a trait peculiar to me, but I think not. I've had good friends who thrived on an element of tension, where just enough uncertainty heightens their senses. I am more aware then. When I get cocky, I stop paying attention.

    One reason that I like agile approaches to software development is that they encourage me not to get cocky. They tell me to take small steps, so I can't run ahead of my understanding. They tell me to find simple solutions, so that I have a better chance of succeeding (and, when I don't, I won't have erred too badly). They tell me to seek continuous feedback, so that I can't fool myself into thinking that all is going smoothly. The red bar cannot be denied! They tell me to integrate my work continuously, so that I can't fool myself about the system at large. They tell me to interact with other developers and with my customer as frequently as I can, so that others can help me, and keep me honest. The whole culture is one of humility and honesty.


    Posted by Eugene Wallingford | Permalink | Categories: Managing and Leading, Running, Software Development

    June 18, 2006 10:20 AM

    Programming as Program Transformation

    I see that Ralph Johnson is giving the Friday keynote talk at ECOOP 2006 this year. His talk is called "The Closing of the Frontier", and the abstract shows that it will relate to an idea that Ralph has blogged about before: software development is program transformation. This is a powerful idea that has emerged in our industry over the last decade or so, and I think that there are a lot of computer scientists who have to learn it yet. I have CS colleagues who argue that most programs are developed essentially from scratch, or at least that the skills our students most need to learn most closely relate to the ability to develop from scratch.

    I'm a big believer in learning "basic" programming skills (most recently discussed here), but I'd like for my students to learn many different ways to think about problems and solutions. It's essential they learn that, in a great many contexts, "Although user requirements are important, version N+1 depends more on version N than it does on the latest requests from the users."

    Seeing Ralph's abstract brought to mind a paper I read and blogged about a few months back, Rich Pattis's "A Philosophy and Example of CS-1 Programming Projects". That paper suggested that we teach students to reduce program specs to a minimum and then evolve successive versions of a program which converges on the program that satisfies all of the requirements. Agile programming for CS1 back in 1990 -- and a great implementation of the notion that software development is program transformation.

    I hope to make this idea a cornerstone of my CS1 course this fall, with as little jargon and philosophizing as possible. If I can help students to develop good habits of programming, then their thoughts and minds will follow. And this mindset helps prepare students for a host of powerful ideas that they will encounter in later courses, including programming languages, compilers, theory, and software verification and validation.

    I also wish that I could attend ECOOP this year!


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

    June 14, 2006 3:49 PM

    Picking a Textbook for Fall

    I've come to realize something while preparing for my fall CS1 course.

    I don't like textbooks.

    That's what some people call a "sweeping generalization", but the exceptions are so few that I'm happy to make one.

    For one thing, textbooks these days are expensive. I sympathize with the plight of authors, most of whom put in many more hours than book sales will ever pay them for. I even sympathize with the publishers and bookstores, who find themselves living in a world with an increasingly frictionless used-book market, low-cost Internet-based dealers, and overseas sellers such as Amazon India. But none of this sympathy changes the fact that $100 or more for a one-semester textbook -- one that was written specifically not to serve as a useful reference book for later -- is a lot. Textbook prices probably have not risen any faster than the rate of tuition and room and board, but still.

    Price isn't my real problem. My real problem is that I do not like the books themselves. I want to teach my course, and more and more the books just seem to get in the way. I don't like the style of the code shown to students. I don't like many of the design ideas they show students. I don't like all the extra words.

    I suppose that some may say these complaints say more about me than about the books, and that would be partly true. I have some specific ideas about how students should learn to program and think like a computer scientist, and it's not surprising that there aren't many books that fit my idiosyncrasy. Sticking to the textbook may have its value, but it is hard to do when I am unhappy at the thought turning another page.

    But this is not just me. By and large, these books aren't about anything. They are about Java or C++ or Ada. Sure, they may be about how to develop software, too, but that's an inward-looking something. It's only interesting if you are already interested in the technical trivia of our discipline.

    This issue seems more acute for CS 1, for a couple of reasons. First, one of the goals of that course is to teach students how to program so that they can use that skill in later courses, and so they tend toward teaching language. More important is the demand side of the equation, where the stakes are so high. I can usually live with one of the standard algorithms books or compilers books , if it gives students a reasonable point of view and me the freedom to do my own thing. In those cases, the book is almost a bonus for the students. (Of course, then the price of the book becomes more distasteful to students!)

    Why use a text at all? For some courses, I reach a point of not requiring a book. Over the last decade or more, I have evolved a way of teaching Programming Languages that no longer requires the textbook with which I started. (The textbook also evolved away from our course.) Now, I require only The Little Schemer, which makes a fun, small, relatively inexpensive contribution to how my students learn functional programming. After a few times teaching Algorithms, I am getting close to not needing a textbook in that course, either.

    I haven't taught CS 1 in a decade, so the support of a strong text would be useful. Besides, I think that most beginning students find comfort at least occasionally in a text, as something to read when today's lecture just didn't click, something to define vocabulary and give examples.

    Introduction to Computing ... A Multimedia Approach

    So, what was the verdict? After repressing my true desires for a few months in the putative interest of political harmony within the department, yesterday I finally threw off my shackles and chose Guzdial and Ericson's Introduction to Computing and Programming with Java: A Multimedia Approach. It is relatively small and straightforward, though a still a bit expensive -- ~ $90. But I think it will "stay out of my way" in the best sense, teaching programming and computing through concrete tasks that give students a chance to see and learn abstractions. Perhaps most important, it is about something, a something that students may actually care about. Students may even want to program. This book passes what I call the Mark Jacobson Test, after a colleague who is a big believer in motivation and fun in learning: a student's roommate might look over her shoulder one night while she's doing some programming and say, "Hey, that looks cool. Whatcha doing?"

    Let's see how it goes.


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

    June 10, 2006 3:29 PM

    Students, Faculty, and the Internet Age

    I've been meaning to write all week, but it turned out to be busy. First, my wife and daughters returned from Italy, which meant plenty of opportunity for family time. Then, I spent much of my office week writing content for our new department website. We were due for a change after many years of the same look, and we'd like to use the web as a part of attracting new students and faculty. The new site is very much an early first release, in the agile development sense, because I still have a lot of work to do. But it fills some of our needs well enough now, and I can use bits and pieces of time this summer to augment the site. My blogging urge was most satisfied this week by the material I assembled and wrote for the prospective students section of the site. (Thanks to the Lord of the Webs for his design efforts on the system.)

    Werner Vogels

    I did get a chance to thumb through the May issue of ACM Queue magazine, where I read with some interest the interview with Werner Vogels, CTO of Amazon. Only recently I had been discussing Vogels as a potential speaker for OOPSLA this or some year soon. I've read enough of Vogels's blog to know that he has interesting things to say.

    At the end of the interview, Vogels comments on recruiting students and more generally on the relationship of today's frontier IT firm to academia. First, on what kind of person Amazon seeks:

    The Amazon development environment requires engineers and architects to be very independent creative thinkers. We are building things that nobody else has done before, so you need to be able to think outside the box. You need to have a strong sense of ownership, because in the small teams in which you will work at Amazon, your colleagues will count on you to pull your weight -- especially when it comes to operating the service that you have built. Can you take responsibility for making this the best it can be?

    Many students these days hear so much about teamwork and "people" skills that they sometimes forget that every team member has to be able to contribute. No one wants a teammate who can't produce. Vogels stresses this upfront. To be able to contribute effectively, each of us needs to develop a set of skills that we can use right now, as well as the ability to pick up new skills with some facility.

    I'd apply the same advice to another part of Vogels's answer. In order to "think outside the box", you have to start with a box.

    Vogels then goes on to emphasize how important it is for candidates to "think the right way about customers and technology. Technology is useless if not used for the greater good of serving the customer." Sometimes, I think that cutting edge companies have an easier time cultivating this mindset than more mundane IT companies. A company selling a new kind of technology or lifestyle has to develop its customer base, and so thinks a lot about customers. It will be interesting to see how companies like Yahoo!, Amazon, and Google change as they make the transition into the established, mainstream companies of 2020.

    On the relationship between academia and industry, Vogels says that faculty and Ph.D. students need to get out into industry in order to come into contact with "the very exciting decentralized computing work that has rocked the operating systems and distributed systems world in the past few years". Academics have always sought access to data sets large enough for them to test their theories. This era of open source and open APIs has created a lot of new opportunities for research, but open data would do even more. Of course, the data is the real asset that the big internet companies hold, so it won't be open in the same way for a while. Internships and sabbaticals are the best avenue open for academics interested in this kind of research these days.


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

    June 02, 2006 9:16 AM

    Programming as Map-Making

    Yesterday evening, I was thinking about map-making, which I had discussed briefly in my blog on Programming as Discovery and Expression. Dick Gabriel discussed map-making as an activity like writing and programming, an act blending discovery and expression. I've long considered the analogy between programming and writing, but the analogy between programming and map-making was new to me. It jumped back into the forefront of mind while walking.

    Programming is a lot like map-making. Cartographers start with the layout of the physical world, the earth and its features, and produce a model for a specific purpose. We programmers start with a snapshot of some part of the world, too, and produce a model for a specific purpose. Like map-makers, we leave out some details, the ones that don't serve our purpose. When we write business software, we create little models of people as objects or entries in a database table, but we leave out all sorts of features. I rarely see a "hair color" attribute on my business objects. Like map-makers, we accentuate other details of interest, such as wage rate and years of service.

    Is there anything for us to learn about programming from this analogy? Have you ever heard of this metaphor before, or seen it discussed somewhere? I'm not thinking of conceptual analogs like "mind maps" and generic modeling, but honest-to-goodness maps, with mercator projections and isobars and roads. I think I'll have to read a bit on the act of cartography to see what value there might be in the analogy.


    Posted by Eugene Wallingford | Permalink | Categories: Software Development

    June 01, 2006 9:44 AM

    Programming as Discovery and Expression

    The RPG Dreamsongs quill

    Recently I pointed you to Dick Gabriel's The Art of Lisp & Writing, which I found when I looked for a Gabriel essay that discussed triggers and Richard Hugo. I must confess that I recommended Dick's essay despite never having read it; then again, I've never been disappointed by one of his essays and figured you wouldn't be, either.

    I read the essay over tortellini last night, and I wasn't disappointed. I learned from his discussion of the inextricable partners in creation, discovery and presentation. I learned about mapmakers and how their job is a lot like an engineer -- and a lot like a writer.

    Most of exploration is in the nature of the locally expected: What is on the other side of that hill is likely to be a lot like what's on this side. Only occasionally is the explorer taken totally by surprise, and it is for these times that many explorers live. Similarly for writers: What a writer thinks up in the next minute is likely to be a lot like what is being thought this minute -- but not always: Sometimes an idea so initially apparently unrelated pops up that the writer is as surprised as anyone. And that's why writers write.

    As anyone who has ever written a program worth writing will tell you, that is also why programmers program. But then that is Dick's point. Further, he reminds us why languages such as Lisp and Smalltalk never seem to die: because programmers want them, need them.

    Gabriel has been writing about programming-and-writing for many years now, and I think that his metaphor can help us to understand our discipline better. For example, by explaining writing as "two acts put together: the act of discovery and the act of perfecting the presentation", the boundaries of which blur for each writer and for each work, we see in relief one way in which "software engineering" and the methodologists who drive it have gone astray. I love how Dick disdains terms such as "software developer", "software design and implementation". For him, it's all programming, and to call it something else simply obscures a lot of what makes programming programming in the first place.

    Reading this essay crystallized in mind another reason that I think Java, Ada, and C++ are not the best (or even okay) choices for CS 1: They are not languages for discovery. They are not languages that encourage play, trying to solve a hard problem and coming to understand the problem in the process of writing the program that solves it. That's the great of of programming, and it is exactly what novice programmers need to experience. To do so, they need a language that lets them -- helps them? -- both to discover and to express. Java, Ada, and C++ are Serious Languages that optimize on presentation. That's not what novice programmers need, and probably not the pros need, either.

    This essay also may explain the recent rise of Ruby as a Programmer's Programming Language. It is a language for both to discovery and expression.

    As usual, Gabriel has explored a new bit of landscape for me, discovered something of value, and given us a map of the land.


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

    May 25, 2006 10:12 AM

    Dumbing Down Recipes

    As a part of seeing my wife and daughters off to Italy, I cooked a few special meals for them on Sunday and Monday. One friend suggested that I needn't have bothered, because they will encounter much better food in Italy, but I think that an unusual meal prepared by Dad is still a nice treat -- and my wife loved not having to think about any meals for the last couple of days of packing and preparing. Besides, I'm not too shabby in the kitchen.

    I like to cook. I'm not an accomplished chef, or anything of the sort, just an amateur who like to work in the kitchen and try new things.

    While blanching asparagus for my last and finest effort of the weekend, I remembered an article that ran in our local paper last March under the headline Cookbooks simplify terms as kitchen skills dwindle. It discusses the dumbing down of cookbooks over the last couple of decades because Americans no longer know the common vocabulary of the kitchen. These days, recipes tend not to use words like "blanch", "dredge", or even "saute", "fold", and "braise", for fear that the casual reader won't have any idea what they mean. Cookbooks that buck the trend must provide detailed glossaries that explain what used to be standard techniques.

    In some ways, this is merely a cultural change. People generally don't spend as much time cooking full meals or from scratch these days, and women in particular are less likely than their mothers to carry forward the previous generation's traditional culinary knowledge. That may not be a good or bad thing, just a difference borne out of technology and society. The article even implicates the digital computer, claiming that because kids grow up with computers these days they expect everything, even their cooking, to be fast. Who knew that our computers were partly responsible for the dumbing down of America's kitchen?

    I sometimes think about connections between cooking and programming, and between recipes and programs. Most folks execute recipes, not create them, so we may not be able to learn much about how learning to programming from learning to cook. But the dumbing down of cooking vocabulary is a neat example for how programs work. When a recipe says to "fold" an ingredient into a mixture, it's similar to making a procedure call. Describing this process using different terms does not change the process, only the primitives used to describe the process. This focus on process, description, and abstraction is something that we computer scientists know and think a lot about.

    In a more general teaching vein, I chuckled in my empathy for this cookbook editor:

    "Thirty years ago, a recipe would say, 'Add two eggs,'" said Bonnie Slotnick, a longtime cookbook editor and owner of a rare-cookbook shop in New York's Greenwich Village. "In the '80s, that was changed to 'beat two eggs until lightly mixed.' By the '90s, you had to write, 'In a small bowl, using a fork, beat two eggs,'" she said. "We joke that the next step will be, 'Using your right hand, pick up a fork and...' "

    Students probably feel that way about programming, but I sometimes feel that way about my students...

    ... which bring me back to my day job. I have reason to think about such issues as I prepare to teach CS 1 for the first time in a decade or so. Selecting a textbook is a particular challenge. How much will students read? What kinds of things will they read. How well can they read? That seems like an odd question to ask of college freshmen, but I do wonder about the technical reading ability of the average student who has questionable background in math and science but wants to "program computer games" or "work with computers". Colleagues complain about what they see as a dumbing down of textbooks, which grow in size, with more and more elaborate examples, while in many ways expecting less. Is this sort of text what students really need? In the end, what I think they really need are a good language reference and lots of good examples to follow, both in the practice of programming and in the programs themselves. It's our job to teach them how to read a language reference and programs.

    My selection of a CS 1 textbook is complicated by the particular politics of the first year curriculum in my department. I need something that feels traditional enough not to alienate faculty who are skeptical of OO, but true enough to OO that Java doesn't feel like an unnecessary burden to students.

    blanching vegetables

    Postscript: Many recipes require that vegetables be blanched -- scalded in boiling water a short time -- before being added to a dish. Blanching stops the enzyme action, which allows them to stay crisp and retain their color and flavor. Here is a simple how-to for blanching. I didn't lear this from my mom or any of the cooks in my family (including my dad); I learned it the old-fashioned way: I ran into the term in a recipe, I wanted to know what it meant, so I looked it up in the cookbook. If we could give our programming students the right sort of reference for looking up the terms and ideas they encounter, we would be doing well. Of course, some students of programming will be like some students of cooking and try to fake it. I don't recommend faking the blanching of asparagus -- it's a temperamental vegetable!


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

    May 23, 2006 4:23 PM

    Quality is Only One Good

    It seems that folks have been discussing a flap between Google and Yahoo about choice in the search engine market. "Choice" has become a loaded term in several political contexts over the last couple of decades, and I suppose that this context is political in its own way.

    I don't have much to say today about the Google, Yahoo, Microsoft situation, but something Jeremy Zawodny said recently struck a chord:

    First off, I agree that companies should compete based on quality. But Microsoft and McDonald's are both shining examples of how that's not necessarily the way it works when "the market" is involved in the decision making. Price and convenience tend to trump quality.

    Far be it from me to defend Microsoft and McDonald's, neither of whose products I use with any frequency. But... it seems Jeremy is saying that companies compete based only on quality, whereas the market introduces unfortunate forces such as price and convenience into the mix.

    Why should companies compete based only on quality?

    Quality is only one good. Other features have value, too. I don't think the market introduces issues such as price and convenience into the equation so much as expose what people really value.

    I think that I value quality, but I also value other things in this world. In particular, I am often a price-sensitive consumer. With two daughters to raise, I sometimes have to make choices based on both quality and price, if I want to save money for other purchases I want to make.

    In the search arena, if Yahoo! or some other company creates the absolute best, highest-quality search engine, but it costs a pretty penny, I may choose a "lower-quality" provider simply to conserve my scarce resources for something else that I value. And I may not suffer at all for my choice; good enough is often good enough.

    We face this kind of choice in software development, of course, and folks like Richard Gabriel have written about the phenomenon's effect in the software world. Agile methodologies encourage us not to build the Perfect Solution if we aren't gonna need it. I suppose that the choice between "do the right thing" and "do the simplest thing" is still an open question in the software world, with many folks not enamored with the agile approach to things, but I think in the long run "do the simplest thing" will win out -- and produce both the most software and the best software.

    This is all basic economics: we have to make choices in a world of scarce resources and conflicting values.

    As something of a disclaimer, while I can pinch pennies with the best of them, I'm not a "least common denominator" kind of guy. I don't eat a lot of fast food, at McDonald's or elsewhere, because I value some things more than the convenience and immediate price savings over some of the alternatives. I'm writing this blog entry on a computer made by a company that has built its reputation on the idea that it makes better products. Users of these products seem prouder than most to be using the better tools. And those of us who use these products pay a small premium to do so. When I buy a new computer, I take quality and price into account, along with a whole host of other factors, including convenience and the intangibles of my experience using the product.

    I value quality, but I value many other things, too.

    (Oh, and if Jeremy didn't mean what I thought he meant, I apologize for dragging him into this. His blog entry was simply the trigger for this piece. For more on triggers in writing, start with this piece by Richard Gabriel. I also recommend the Hugo book that Richard cites.)


    Posted by Eugene Wallingford | Permalink | Categories: General, Software Development

    May 17, 2006 3:10 PM

    Fifteen Compilers in Fifteen Weeks

    Our semester ended a couple of weeks ago. It was busier than usual, for a variety of reasons, but my compiler course was one of the enjoyable experiences. Of course, my students will say that my compiler course was one of the major reasons that their semester was busier than usual.

    A compiler is usually the largest piece of software an undergraduate CS student will write. Some of my students may have written other large programs, in other senior project courses, but I doubt they've written larger, and certainly not in smaller teams. (Most worked in pairs.) Several commented that they learned more just trying to write such a large program than they had in any of my courses. That doesn't surprise... It's one of the main reasons that I think it's essential for every undergrad to take a project course of this sort. There is no substitute.

    After watching my students struggle to meet deadlines and to deliver assigned functionality, I've been thinking about using agile methods to write a compiler. Even with occasional suggestions from me for how to manage their projects, students fell behind. It is just too easy for students to fill their time with other, more immediate demands and watch project deadlines such as "table-driven parser, due in three weeks" get closer and closer.

    Then there were times when students made a good-faith effort to estimate how long a task would take them, only to be off by an order of magnitude. The code for the table-driven parser isn't so bad, but, boy, does that table take a long time to build!!

    Throughout the semester, I made several common suggestions, ones that will sound familiar: take small steps through the spec; have unit tests for each element you build, so that you won't be so afraid to make changes. But next time, I think I may go one step farther and make two other agile practices cornerstones of the course: short iterations and small releases. How about a deliverable every week!?

    Figuring out how best to define the stories and then order them for implementation will be the challenge. In my mind's eye, I'd like for each release to create a complete compiler, for some linguistically meaningful definition of "complete". Start with such a subset of the language that we can build a compiler for it with little or no overhead. Then, add to the language grammar bit by bit in ways that slowly introduce the ideas we want to study and implement. Eventually we need a more principled form of scanning; eventually, we need a parser that implements a derivation explicitly. The issues would not have to arise in the traditional front-to-back order of a compiler course; why do we necessarily have to build a fancy parser before implementing a rudimentary run-time system?

    Can this work for something like the parsing table? Adding grammar elements to the language piecemeal can have odd effects on the parsing rules. But I think it's possible.

    And if I seem stuck on the table-driven parser in all of my examples, this may be a result of the fact that I still like for students to implement their parsers by hand. I know that we could go a lot farther, and do a lot more with code generation and optimization, if we built our parsers using a tool such as Yacc, JavaCC, or SableCC. But I can't shake the feeling of the value that comes from implementing a non-trivial parser by hand. Maybe I'm a dinosaur; maybe my feelings will change in the next eighteen months before I teach the course again.

    Though I've been thinking some of these thoughts since last summer, I have to give credit to Jeremy Frens and Andrew Meneely of Calvin College, who presented a paper at this year's SIGCSE called Fifteen Compilers in Fifteen Days (also available from the ACM Digital Library). I'm not sure I'd want to follow their course outline very closely, but they do have some experience in sequencing the stories for the project in a way that introduces complexities in an interesting way. And the idea is just what I think we need: fifteen compilers in fifteen weeks.


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

    May 09, 2006 5:07 PM

    Different Kinds of Lazy and Dumb

    Sometime in the last month, I came across a link to an article that is a couple of years old, Why Good Programmers Are Lazy and Dumb. I like to read that kind of article every once in a while, even if I've seen the general ideas before. Usually, such an article hits me in a particular way according to my current frame of mind. Here are the ideas that stood out for me this weekend:

    • Balance. Without it, we usually go astray.

    • Lazy? "... because only lazy programmers will want to write the kind of tools that might replace them in the end."

      But you can't be so lazy that you are unwilling to write those tools, or to refactor your code, to save time in the future. You have to be forward-thinking lazy. You Aren't Gonna Need It is an admonition against doing work too soon. But sometimes, you do need it.

    • Dumb? "The less you know, the more radical will your approaches become...." You know, beginner's mind and all that.

      But you can't be so dumb that you don't have the raw material out of which to propose a radical solution. You can only think outside the box when you start with a box.

    Just as it's true that if you can't handle the right kind of pain you'll have a hard time getting better at much of anything, it's true that if you can't find the balance between the rights kind of lazy and dumb, you'll have a hard time taking your skills to the next level.


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

    April 30, 2006 12:04 PM

    Process on My Mind

    Jesus Christ Superstar

    My family and I watched the Tim Rice/Andrew Lloyd Webber rock opera "Jesus Christ Superstar" this weekend. Both of my daughters are into the theater, having performed a few times and seen most of the local children's theater's productions over the last many years. My older daughter vaguely remembers a stage production we saw a few years ago at an excellent local playhouse and wanted to see the show again. Our local library had two versions, the original 1973 movie and a 2000 London theatrical performance staged for television. Fortunately, we all like the music, so watching the same show on back-to-back nights was just fine.

    Watching two versions so close in time really made the differences in tone, characterization, and staging stand out in great relief. The newer version took a European viewpoint, with the Romans as fascist/Nazi-like overlords and the common people seeking a revolution. The older version focused more on the personal struggles of the main characters -- Jesus, Mary, and especially Judas -- as they tried to come to grips with all that was happening around them.

    For some reason, this brought to mind a short blog entry called Process as theatre written by Laurent Bossavit nearly two years ago. Laurent considers the differences between Extreme Programming as described in Kent Beck's original book and as practiced by Kent and others since, and compares them to the script of a play like "Hamlet". The script stays the same, but each staging makes its own work of art. The two videos I watched this weekend were at the same time both the same play and very different plays. (I was proud when my younger daughter recognized this and was able to express the two sides.)

    Folks who feel compelled to follow every letter of every rule of a methodology often find themselves burning out and becoming disillusioned. Or, even when they are able to keep the faith, they find it difficult to bring others into the process, because those folks don't feel any need to be so limited.

    On the other hand, we've all seen performances that take too many liberties with a script or story -- and instinctively feel that something is wrong. Similarly, we can't take too many liberties with XP or other methodologies before we are no longer working within their spirit. In XP, if we give up too many restrictions, we find that some of the remaining practices lose their effectiveness without the balancing effects of what we've removed.

    As in so many things, striking the right balance between all or nothing is the key. But we start from a healthier place when we realize that a development process consists of both script and production, fixed and dynamic elements working together to create a whole.

    I had forgotten that Laurent's blog entry refers to the book Artful Making. In an interesting confluence, I just this week asked our library to purchase a copy of this book so that I can read it over the summer. Now I'm even more eager.

    Josh Mostel as King Herod

    Oh, and on the two versions of "Superstar": call me an old fogey, but I still love the 1973 movie. Larry Marshall as Simon Zealotes gives an awesome performance in his highlighted scene, and Josh Mostel delivers one of the all-time great comedic song-and-dance performances as King Herod. "Get out of my life!"


    Posted by Eugene Wallingford | Permalink | Categories: General, Software Development

    April 09, 2006 10:31 AM

    A Guilty Pleasure, Language-Style

    While doing a little reading to end what has been a long week at the office, I ran across a pointer to Steve Yegge's old piece, Tour de Babel, which has recently been touched up. This is the third time now that Yegge's writing has come recommended to me, and I've enjoyed the recommended article each time. That means I need to add his blog to my newsreader.

    This was my favorite quote from the article, a perfect thought with which to end the week:

    Familiarity breeds contempt in most cases, but not with computer languages. You have to become an expert with a better language before you can start to have contempt for the one you are most familiar with.

    So if you don't like what I am saying about C++, go become an expert at a better language (I recommend Lisp), and then you'll be armed to disagree with me. You won't, though. I'll have tricked you. You won't like C++ anymore...

    I know that this is the sort of inflammatory, holier-than-thou pronouncement that smug Lisp weenies make all the time, and that it doesn't do anything to move a language discussion forward. But from all I've read by Steve, he isn't a language bigot at all but someone who seems to like lots of languages for different virtues. He even speaks kindly of C++ and Java when they are discussed in certain contexts.

    Even though I know I shouldn't like these sorts of statements, or give them the bully pulpit of my ever-so-popular blog, I give in to the urge. They make me smile.

    I myself am not a smug Lisp weenie. However, if you replaced "Lisp" with "Smalltalk" or "Scheme" in the quoted paragraph, I would be smiling even wider. (And if you don't know why replacing "Lisp" with "Scheme" in that sentence would be a huge deal to a large number of Lisp devotees, well, then you just don't understand anything at all about smug Lisp weenies!)

    Pardon me this guilty pleasure.


    Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

    April 07, 2006 11:33 PM

    Back to the Basics. Accelerated

    The SIGCSE mailing list has been alive this week with a thread that started with pseudocode, moved to flowcharts, and eventually saddened a lot of readers. At the center of the thread is the age-old tension among CS educators that conflates debates between bottom-up and top-down, low-level and high-level, machine versus abstraction, and "the fundamentals" with "the latest trends". I don't mean to rehash the whole thread here, but I do want to share my favorite line in the discussion.

    Suffice to say: Someone announced an interest in introducing programming via a few weeks of working in pseudocode, which would allow students to focus on algorithms without the distraction of compilers. He asked for advice on tools and resources. A group of folks reported having had success with a similar idea, only using flowchart tools. Others reported the advantages of lightweight assembly-language style simulators. The discussion became a lovefest for the lowest-level details in CS1.

    My friend and colleague Joe Bergin, occasionally quoted here, saw where this was going. He eventually sent an impassioned and respectful message to the SIGCSE list, imploring folks to look forward and not backwards. In a message sent to a few of us who are preparing for next week's ChiliPLoP 2006 conference, he wrote what became the closing salvo in his response.

    The pseudocode thread on the SIGCSE list is incredibly depressing. ... Why not plugboards early? Why not electromechanical relays early? Why not abacus early?

    An "abacus-early" curriculum. Now, there's the fundamentals of computing! Who needs "objects first", "objects early", "procedures early", "structured programming", ...? Assignment statements and for-loops are johnny-come-latelys to the game. Code? Pshaw. Let's get back to the real basics.

    Joe, you are my hero.

    (Of course, I am being facetious. We all know that computing reached its zenith when C sprang forth as whole cloth from Bell Labs.)

    Am I too young to be an old fogey tired of the same old discussions? Am I too young to be a guy who likes to learn new things and help students do the same?

    I can say that I was happy to see that Joe's message pulled a couple of folks out of the shadows to say what really matters: that we need to share with students the awesome beauty and power of computing, to help them master this new way of thinking that is changing the world as we live. All the rest is details.


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

    April 06, 2006 6:46 PM

    Different Kinds of Pain

    The other night at dinner, I was telling my family about the state of my legs after my most recent run, and I said, "My legs don't hurt, but my hamstrings are sore." My younger daughter, Ellen, responded, "Um, Dad, your hamstring is part of your leg." And I was caught. Fun was had by all at my expense.

    Of course, I was talking about different kinds of pain. I've been thinking about different kinds of pain a lot lately. As I mentioned in my last post, I have been having trouble with my hamstrings. I have not suffered from a running injury in the three-plus years since I developed a larger commitment to running, but I've felt plenty of pain. Whenever we push our bodies farther than they are used to going, they tend to talk back to us in the form of muscle soreness and maybe even a little joint soreness. That pain is a natural part of the growth process, and if we can't handle that sort of pain then we can't get better -- more speed, more stamina. Oh, I suppose that we might be able to get better slowly, but so slowly that it wouldn't be any fun. Even still, we runners have to listen to their bodies and let them tell us when to lighten up. I live with this sort of pain periodically, as it is a part of the fun.

    This is a different sort of pain than the pain we feel when something is wrong with the body. Last week, my hamstrings hurt. Walking was painful at times, and going upstairs was torturous. This is the kind of pain that evolved to tell us our bodies are broken in a way that wasn't helping. Listening to this kind of pain is crucial, because unheeded the underlying cause can debilitate us. When we feel this kind of pain, we need to "get better", not get "better".

    This week I have been talking with students in my compilers class. They are feeling a kind of pain -- the pain of a large project, larger than they've ever worked on, that involves real content. If they design the parsing table incorrectly, or implement the table-driven parsing algorithm incorrectly, then their programs won't work. To their credit, they all see this sort of pain as useful, the sort of pain you feel when you are getting better. "I've learned more about Java programming and object-oriented design than I've ever learned before." They realize that, in this case, less pain would be worse, not better. Still, I feel for them, because I recall what those first few experiences with non-trivial programs felt like.

    For my agile software development readers: I know that I haven't written much about agile in a while, but I can say that many of my students are also experiencing the pain that comes from not using the agile practices that they know about. Taking small steps, using unit tests, and getting as much feedback from their code as often as possible -- all would make their lives better. There is nothing like trying to debug several hundred lines of tightly-coupled code for the first time and needing to track down why Rule 42 of 200 doesn't seem to be firing at the right time!

    This is also advising time, as students begin to register for fall courses. Sometimes, the best course for a student will be painful, because it will stretch him or her in a way that the mind is not used to. But that may be just what the student needs to get over the hump and become a top-notch computer scientist!

    These encounters with various kinds of pain remind me of an essay by Kathy Sierra from a month or so ago. One of her central points is that, to become really good at a task, you must practice the parts that you are weakest at -- you have to choose pain. Most of us prefer to practice that with which we are already comfortable, but then we don't stretch our (programming, piano-playing, golfing, running) muscles enough to grow. I suspect that it's even worse than that, that by repeatedly practicing skills we are already good at we drive our muscles into a rut that leaves us worse, not better. I see that happen in my running every so often, and it probably happens to my programming, too.

    But is all the psychic pain we feel when taking a compilers course or learning to program a good sign? Probably not. We do need to choose tasks to master for which we are well suited, that we like enough to work on at all. If you really have no affinity for abstraction and problem solving, then computer science probably isn't for you. You'll not like doing it, no matter how expert you become. But after selecting a task that you can be good at or otherwise interested in, you after to be ready to take on the growing pains that come with mastering it. Indeed, you have to seek out the things you aren't good at and whip them. (*)

    I hope you have the chance to feel the right kind of pain soon. But not for long -- be sure to move on to the fun of getting better as soon as possible.

    ~~~~~

    (*) I do offer one caveat, though. It is too easy to tell ourselves, "Oh, I don't like that" as a way to avoid finding out whether we might like something enough in practice. I don't know how many times people have said, upon hearing that I ran 20 miles that morning, "Oh, I can't run long distances" or "I don't like to run at all". I usually smile politely, but sometimes I'll let them know that I didn't know I liked it until I had done it for a while. I used to make jovial fun of my friends who ran. Then I did a little for ulterior reasons and thought, "Hmmm...", and then I did more and more. Sometimes we need to try something out for a while just to know it well enough to judge it.


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

    April 02, 2006 4:21 PM

    Teaching XP in CS 1 -- Back in 1990!

    A couple of days ago I was tracking down an article that had been mentioned in a thread on the SIGCSE mailing list and ran across Rich Pattis's paper, "A Philosophy and Example of CS-1 Programming Projects" (pdf), from the February 1990 issue of the ACM SIGCSE Bulletin. Having recently written about Rich's work, I couldn't resist taking it home for a weekend read. Not surprisingly, I am glad I did.

    On its face, this paper is relatively unassuming. It describes a project that he assigns to his CS 1 students as an example of how he thinks about projects. Reading it reminded me of the sort of simplicity I associate with Ward Cunningham. But I was amazed to see Rich talk about two ideas that have been discussed everywhere in CS education for the last few years.

    Section 2 is titled "Using Packages in Projects". It lays out Rich's philosophy of projects, which consists of at least two key ideas:

    • Students "are more motivated and enthusiastic about writing programs whose significance and usefulness they can plainly understand."

      Long-time Knowing and Doing readers know that this topic is often on my mind.

    • Real problems are complex and may require code and ideas that are beyond the students' current level of understanding. But "one way to simplify a programming project is to provide students with packages that contain useful operations that are beyond their ability to write."

      Anyone who has been trying to teach OOP faithfully in the first year recognizes this as a central theme.

    Then, Section 5 describes the software "methodology" that Rich taught his students, which he called Stepwise Enhancement. If you read this paper today, you'll say to yourself, wait a minute, that's XP! Consider these fragments:

    ... students first must reduce the program specifications to a minimum, concentrating on their main structural features and ignoring all the complicated details that will make the program difficult to write. Then they design, implement, and test ... a complete version of the program that meets these simplest specifications.

    The students continue repeating this process - at each stage enhancing the specifications and writing an enhanced program that meets these new specifications - until they have solved the complete problem described in the original specifications.

    At every stage they are making small additions or modifications to an already correct (for the simplified specifications) program.

    Fundamentally the stepwise-enhancement technique is useful because it is easier to design, implement, and test a series of increasingly more sophisticated complete programs than it is to attempt writing one large program that solves the original problem specifications at the outset...

    This technique also allows students to test their original ideas on how to solve the main features of the problem in a simple program first. They receive feedback, at very short intervals, that tells them whether or not they are on the correct path to a solution program. ... such feedback is critical for students who are learning in parallel the language features and how to use these features when writing programs.

    As students gain more programming experience, it will become more obvious to them what are the important structural features in specifications and what are the complicated details....

    At the end of each stage, students should have a working program that they can test on the computer to ensure that it correctly solves the problem at that stage.... If they do not finish a program, they still should have a running program that solves a simpler problem.

    I could quote more, but there is something known as "fair use". Besides, you should just go read the paper, which you can find in the ACM Digital Library. Bonus points to the reader who finds the most XP values and practices in this three quarters of a page of text! Plus, you get a sense of the practical experience Rich had gained while teaching this style of development.

    I haven't even mentioned the sample project, a simple cardioverter-defibrillator. Now that I am on deck to teach our CS1 course, I have a great place to adapt and use this project when teaching about selection and repetition. After reading this paper, I realize how much fun I will have going back to my old CS1 notes, ten years old and older, and recalling how I was teaching elementary patterns and little bits of agile methods back then. I hope that I do an even better job of teaching CS1 after my experiences from the last decade.

    Rich wrote this paper almost 17 years ago -- which should remind all of us who are trying to do new things that there isn't much that is all that new. We have a lot to learn from what folks were doing before our new ideas came along. You just have to know where to look. Considering that guys like Rich and the folks he hangs out with are usually thinking about big ideas and how they might help us improve CS education before anyone else, any CS educator would do well to keep an eye on what they were doing a few years ago. And whatever they are doing right now, well, we'll probably all be doing that in a few years.


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

    March 31, 2006 12:19 PM

    Getting My Groove Back

    To soothe my bruised ego, yesterday evening I did a little light blog reading. Among the articles that caught my attention was Philip Greenspun's Why I love teaching flying more than software engineering. People learning to fly want to get better; I'm guessing that most of them want to become as good as they possibly can. (Just like this guy wanted to make as good a product as possible.) Philip enjoys teaching these folks, more so than teaching students in the area of his greatest expertise, computing, because the math and computing students don't seem to care if they learn or not.

    I see students who will work day and night until they become really good software developers or really good computer scientists, and the common thread through their stories is an internal curiosity that we can't teach. But maybe we can expose them to enough cool problems and questions that one will kick their curiosity into overdrive. The ones who still have that gear will do the rest. Philip worries that most students these days "are satisfied with mediocrity, a warm cubicle, and a steady salary." I worry about this, too, but sometimes wonder if I am just imagining some idyllic world that never has existed. But computer science is so much fun for me that I'm sad that more of our students don't feel the same joy.

    While reading, I listened to Olin Shivers's talk at Startup School 2005, "A Random Walk Through Startup Space" (mp3). It had been in my audio folder for a while, and I'm glad I finally cued it up. Olin gives lots of pithy advice to the start-up students. Three quotes stood out for me yesterday:

    • At one point, Olin was talking about how you have to be courageous to start a company. He quoted Paul Dirac, who did "physics so beautiful it will bring tears to your eyes", as saying

      Scientific progress advances in units of courage, not intelligence.

    • Throughout his talk, Olin spoke about how failure is unavoidable for those who ultimately succeed.
      ... to start a business, you've got to have a high tolerance for feeling like a moron all the time.

      And how should you greet failure when you're staring it in the face?

      Thank you for what you have taught me.

    Next, I plan to listen to Steve Wozniak's much-blogged talk (mp3). If I enjoy that one as much as I enjoyed Shivers's, I may check out the rest of them.


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

    March 17, 2006 9:57 AM

    A Metaphor Lost

    If you've read my blog for long, you know that I like a good metaphor. We can often learn something useful about one system by considering it as another kind of system and seeing what kind of questions this new conception leads us to ask.

    "Software engineering" is a metaphor, even if many folks take it for granted as reality. I've never been all that fond of the metaphor, though we certainly can learn something about how to develop software by considering how engineers make things. But my experience with commercial engineering projects on university campuses has never felt like how I do or might build software.

    My latest experience -- with the renovation of an old building on campus as a new home for my department -- has illustrated yet again why we should not limit ourselves to engineering as the model for how we make software.

    This building project is now over six months late. Each time the schedule is adjusted, it seems to fall behind again within the month. Communication among the various units responsible for, and affected by, project has been abysmal. Changes were made to plans, but these changes did not propagate to everyone who needed to know and as a result work plans were often out of sync. Sometimes, folks knew about a change but had no incentive to find out how the change affected what they should be doing -- so they didn't.

    My favorite example of this was when a service closet was converted to a server room for my department. The change was made in conjunction with building architects, and the updated drawings for the building now showed a "server room". At least some of folks responsible for building infrastructure were aware of the change, but they either assumed that the change didn't affect them or figured they didn't want to know how it would. Plans proceeded as they were, with no provision made for the necessary cooling or power to the room. As the time came for us to move in, we increasingly pressed for these changes to the room, which would now be costlier to implement, both in time and money.

    I know, this is only an anecdote, one experience by one person with one project. It hardly serves as a suitable logical basis for arguing that a seemingly useful idea should be discarded. But this experience is representative others I have had, and also representative of experiences had by many others on this and other campuses with building construction and renovation. It is a now banal joke on campus that we should add months to each target date we are given for the completion of projects.

    Don't get me wrong. These are not bad people. I think all are trying to do their jobs well under demanding circumstances. But as Mary Poppendieck reported in a widely read paper on lean construction, the system doesn't work in a way that makes smooth, timely projects all that likely. Projects are complicated, plans are tightly coupled, and pipelines are sensitive to small changes in expectation. That's just how the world really is.

    This is one of the dangers inherent in metaphor: unreality. It is easy for us in software to idealize other disciplines and how they work. One result is that we beat ourselves up for how we could do better is only we were more like "them", for some broad spectrum of thems. Architecture -- isn't it just dreamy? Engineering -- tough, rigid, clean, controlled. But we need to make metaphors with our eyes carefully tuned to how the world really is in those other disciplines, not only the ideas but the daily practices and experiences. Otherwise, we are bound to create unrealistic expectations for how we do what we do, and how well we do it.

    And ultimately we lose out on the learning to be had from the metaphor, because we will miss the opportunity to ask ourselves the questions that will help us to understand better what we do.


    Posted by Eugene Wallingford | Permalink | Categories: Software Development

    March 10, 2006 5:37 PM

    Students Paying for Content

    Education is an admirable thing,
    but it is well to remember from time to time
    that nothing worth knowing can be taught.
    -- Oscar Wilde

    Recently I have been having an ongoing conversation with one of my colleagues, a senior faculty member, about teaching methods. This conversation is part of a larger discussion of the quality of our programs and the attractiveness of our majors to students.

    In one episode, we were discussing the frequency with which one quizzes and exams the class. Some of our math professors quiz almost daily, and even some CS professors give substantial quizzes every week. My colleague thinks is a waste of valuable class time and a disservice to students. I tend to agree, at least for most of our CS courses. When we assess students so frequently for the purposes of grading, the students become focused on assessment and not on the course material. They also tend not to think much about the fun they could be having writing programs and understanding new ideas. They are too worried about the next quiz.

    My colleague made a much stronger statement:

    Students are paying for content.

    In an interesting coincidence, when he said this I was preparing a class session in which my students would do several exercises that would culminate in a table-driven parser for a small language. We had studied the essential content over the previous two weeks: first and follow sets, LL(1) grammars, semantic actions, and so on.

    I don't think I was wasting my students time or tuition money. I do owe them content about compilers and how to build them. But they have to learn how to build a compiler, and they can't learn that by listening to me drone on about it at the front of the classroom; they have to do it.

    My colleague agrees with me on this point, though I don't think he ever teaches in the way I do. He prefers to use programming projects as the only avenue for practice. Where I diverge is in trying to help students gain experience doing in a tightly controlled environment where I can give almost immediate feedback. My hope is that this sort of scaffolded experience will help them learn and internalize technique more readily.

    (And don't worry that my students lack for practical project experience. Just ask my compiler students, who had to submit a full parser for a variant of Wirth's Oberon-0 language at 4 PM today.)

    I think that our students are paying for more than just content. If all they need is "dead" content, I can give them a book. Lecture made a lot of sense as the primary mode of instruction back when books were rare or unavailable. But we can do better now. We can give students access to data in a lot of forms, but as expert practitioners we can help them learn how to do things by working with them in the process of doing things.

    I am sympathetic to my colleague's claims, though. Many folks these days spend far too much time worrying about teaching methodology than about the course material. The content of the course is paramount; how we teach it is done in service of helping students learn the material. But we can't fall into the trap of thinking that we can lecture content and magically put it into our students' heads, or that they can magically put it there by doing homework.

    This conversation reminded me of a post on learning styles at Tall, Dark, and Mysterious. Here is an excerpt she quotes from a cognitive scientist:

    What cognitive science has taught us is that children do differ in their abilities with different modalities, but teaching the child in his best modality doesn't affect his educational achievement. What does matter is whether the child is taught in the content's best modality. All students learn more when content drives the choice of modality.

    The issue isn't that teaching a subject, say, kinesthetically, doesn't help a kinesthetic learner understand the material better; the issue is that teaching material kinesthetically may compromise the content.

    Knowledge of how to do something sometimes requires an approach different from lecture. Studio work, apprenticeship, and other forms of coached exercise may be the best way to teach some material.

    Finally, that post quotes someone who sees the key point:

    Perhaps it's more important for a student to know their learning style than for a teacher to teach to it. Then the student can make whatever adjustments are needed in their classroom and study habits (as well as out of classroom time with the instructor).

    In any case, a scientist or a programmer needs to possess both a lot of declarative knowledge and a lot of procedural knowledge. We should use teaching methods that best help them learn.


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

    February 20, 2006 6:48 PM

    Changing How People Think

    Pascal Van Cauwenberghe writes a bit about agile development, lean production, and other views of software engineering. He recently quoted the Toyota Way Fieldbook as inspiration for how to introduce lean manufacturing as change. I think that educators can learn from Pascal's excerpt, too.

    ... we're more likely to change what people think by changing what they do, rather than changing what people do by changing what they think.

    I can teach students about object-oriented programming, functional programming, or agile software development. I can teach vocabulary, definitions, and even practices and methodologies. But this content does not change learners "deeply held values and assumptions". When they get back into the trenches, under the pressure of new problems and time, old habits of thought take over. No one should be surprised that this is true for people who are not looking to change, and that is most people. But even when programmers want to practice the new skill, their old habits kick in with regularity and unconscious force.

    The Toyota Way folks use this truth as motivation to "remake the structure and processes of organizations", with changes in thought becoming a result, not a cause. This can work in a software development firm, and maybe across a CS department's curriculum, but within a single classroom this truth tells us something more: how to orient our instruction. As an old pragmatist, I believe that knowledge is habit of thought, and that the best way to create new knowledge is to create new habits. This means that we need to construct learning environments in which people change what they do in practical, repeatable ways. Once students develop habits of practice, they have at their disposal experiences that enable them to think differently about problems. The ideas are no longer abstract and demanded by an outside agent; they are real, grounded in concrete experiences. People are more open to change when it is driven from within than from without, so this model increases the chance that the learner entertain seriously the new ideas that we would like them to learn.

    In my experience, folks who try XP practices -- writing and running tests all the time, refactoring, sharing code, all supported by pair programming and a shared culture of tools and communication -- are more likely to "get" the agile methods than are folks to whom the wonderfulness of agile methods is explained. In the end, I think that this is true for nearly all learning.


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

    February 16, 2006 3:23 PM

    Eat *That* Dog Food

    Eric Sink tells one of the best stories ever to illustrate the idea of eating your own dog food. Go read the whole paper and story, but I can set up the punchline pretty quickly: Table saws are powerful, dangerous tools. Many woodworkers lose fingers every year using table saws. But...

    A guy named Stephen Gass has come up with an amazing solution to this problem. He is a woodworker, but he also has a PhD in physics. His technology is called Sawstop. It consists of two basic inventions:
    • He has a sensor which can detect the difference in capacitance between a finger and a piece of wood.
    • He has a way to stop a spinning table saw blade within 1/100 of a second, less than a quarter turn of rotation.

    The videos of this product are amazing. Slide a piece of wood into the spinning blade, and it cuts the board just like it should. Slide a hot dog into the spinning blade, and it stops instantly, leaving the frankfurter with nothing more than a nick.

    Here's the spooky part: Stephen Gass tested his product on his own finger! This is a guy who really wanted to close the distance between him and his customers.

    Kinda takes the swagger out of your step for using your own blogging tool.

    Eric's paper is really about software developers and their distance from users. His title, Yours, Mine and Ours, identifies three relationships developers can have with the software they write vis-á-vis the other users of the product. Many of his best points come in the section on UsWare, which is software intended for use by both end users and the developers themselves. Eric is well-positioned to comment on this class of programs, as his company develops a version control tool used by his own developers.

    It's easy for developers to forget that they are not like other users. I know this danger well; as a university faculty need to remind myself daily that I am not like my students, either in profile or in my daily engagement with the course material.

    I like his final paragraph, which summarizes his only advice for solving the ThemWare/UsWare problems:

    Your users have things to say. Stop telling them how great your software is and listen to them tell you how to make it better.

    We all have to remind ourselves of this every once in a while. Sadly, some folks never seem to. Many faculty assume that they have nothing to learn from what their students are saying, but that is almost always because they aren't really listening. Many universities spend so much time telling students why they should come there that they don't have the time or inclination to listen to students say what would make come.

    I also learned an interesting factoid about State Farm Insurance, the corporate headquarters for which are located down I-74 from Eric's home base of Urbana, Illinois. State Farm is also a major corporate partner of the IT-related departments at my university, including the CS department. They work hard to recruit our students, and they've been working hard to help us with resources when possible. The factoid: State Farm is Microsoft's largest non-government customer. [In my best Johnny Carson imitation:] I did not know that. As a result of this fact, Microsoft has an office in the unlikely location of Bloomington, Illinois.

    Despite an obvious interest in hiring folks with experience using Microsoft tools, State Farm has never pressured us to teach .NET or C# or VisualStudio or any particular technology. I'm sure they would be happy if we addressed their more immediate needs, but I am glad to know that they have left decisions about curriculum to us.

    That said, we are beginning to hear buzz from other insurance companies and banks, most located in Des Moines, about the need for student exposure to .NET. We probably need to find a way to give our students an opportunity to get experience here beyond VB.NET and Office. Where is that link to Mono...


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

    February 08, 2006 2:23 PM

    Functional Programming Moments

    I've been having a few Functional Programming Moments lately. In my Translation of Programming Languages course, over half of the students have chosen to write their compiler programs in Scheme. This brought back fond memories of a previous course in which one group chose to build a content management system in Scheme, rather than one of the languages they study and use more in their other courses. I've also been buoyed by reports from professors in courses such as Operating Systems that some students are opting to do their assignments in Scheme. These students seem to have really latched onto the simplicity of a powerful language.

    I've also run across a couple of web articles worth noting. Shannon Behrens wrote the provocatively titled Everything Your Professor Failed to Tell You About Functional Programming. I plead guilty on only one of the two charges. This paper starts off talking about the seemingly inscrutable concept of monads, but ultimately turns to the question of why anyone should bother learning such unusual ideas and, by extension, functional programming itself. I'm guilty on the count of not teaching monads well, because I've never taught them at all. But I do attempt to make a reasonable case for the value of learning functional programming.

    His discussion of monads is quite nice, using an analogy that folks in his reading audience can appreciate:

    Somewhere, somebody is going to hate me for saying this, but if I were to try to explain monads to a Java programmer unfamiliar with functional programming, I would say: "Monad is a design pattern that is useful in purely functional languages such as Haskell.

    I'm sure that some folks in the functional programming community will object to this characterization, in ways that Behrens anticipates. To some, "design patterns" are a lame crutch object-oriented programmers who use weak languages; functional programming doesn't need them. I like Behrens's response to such a charge (emphasis added):

    I've occasionally heard Lisp programmers such as Paul Graham bash the concept of design patterns. To such readers I'd like to suggest that the concept of designing a domain-specific language to solve a problem and then solving that problem in that domain-specific language is itself a design pattern that makes a lot of sense in languages such as Lisp. Just because design patterns that make sense in Java don't often make sense in Lisp doesn't detract from the utility of giving certain patterns names and documenting them for the benefit of ... less experienced programmers.

    His discussion of why anyone should bother to do the sometimes hard work needed to learn functional programming is pretty good, too. My favorite part addressed the common question of why someone should willingly take on the constraints of programming without side effects when the freedom to compute both ways seems preferable. I have written on this topic before, in an entry titled Patterns as a Source of Freedom. Behrens gives some examples of self-imposed cosntraints, such as encapsulation, and how breaking the rules ultimately makes your life harder. You soon realize:

    What seemed like freedom is really slavery.

    Throw off the shackles of deceptive freedom! Use Scheme.

    The second article turns the seductiveness angle upside down. Lisp is Sin, by Sriram Krishnan, tells a tale being drawn to Lisp the siren, only to have his boat dashed on the rocks of complexity and non-standard libraries again and again. But in all he speaks favorably of ideas from functional programming and how they enter his own professional work.

    I certainly second his praise of Peter Norvig's classic text Paradigms of AI Programming.

    I took advantage of a long weekend to curl up with a book which has been called the best book on programming ever -- Peter Norvig's Paradigms of Artificial Intelligence Programming: Case Studies in Common Lisp. I have read SICP but the 300 or so pages I've read of Norvig's book have left a greater impression on me than SICP. Norvig's book is definitely one of those 'stay awake all night thinking about it' books.

    I have never heard anyone call Norvig's book the best of all programming books, but I have heard many folks say that about SICP -- Structure and Interpretation of Computer Programs, by Abelson and Sussman. I myself have praised Norvig's book as "one of my favorite books on programming", and it teaches a whole lot more than just AI programming or just Lisp programming. If you haven't studied, put it at or near the top of your list, and do so soon. You'll be glad you did.

    In speaking of his growth as a Lisp programmer, Krishnan repeats an old saw about the progression of a Lisp programmer that captures some of the magic of functional programming:

    ... the newbie realizes that the difference between code and data is trivial. The expert realizes that all code is data. And the true master realizes that all data is code.

    I'm always heartened when a student takes that last step, or show that they've already been there. One example comes to mind immediately: The last time I taught compilers, students built the parsing tables for the compiler by hand. One student looked at the table, thought about the effort involved in translating the table into C, and chose instead to write a program that could interpret the table directly. Very nice.

    Krishnan's article closes with some discussion of how Lisp doesn't -- can't? -- appeal to all programmers. I found his take interesting enough, especially the Microsoft-y characterization of programmers as one of "Mort, Elvis, and Einstein". I am still undecided just where I stand on claims of the sort that Lisp and its ilk are too difficult for "average programmers" and thus will never be adoptable by a large population. Clearly, not every person on this planet is bright enough to do everything that everyone else does. I've learned that about myself many, many times over the years! But I am left wondering how much of this is a matter of ability and how much is a matter of needing different and better ways to teach? The monad article I discuss above is a great example. Monads have been busting the chops of programmers for a long time now, but I'm betting that Behrens has explained it in a way that "the average Java programmer" can understand it and maybe even have a chance of mastering Haskell. I've long been told by colleagues that Scheme was too abstract, too different, to become a staple of our students, but some are now choosing to use it in their courses.

    Dick Gabriel once said that talent does not determine how good you can get, only how fast you get there. Maybe when it comes to functional programming, most of us just take too long to get there. Then again, maybe we teachers of FP can find ways to help accelerate the students who want to get good.

    Finally, Krishnan closes with a cute but "politically incorrect analogy" that plays off his title:

    Lisp is like the villainesses present in the Bond movies. It seduces you with its sheer beauty and its allure is irresistible. A fleeting encounter plays on your mind for a long, long time. However, it may not be the best choice if you're looking for a long term commitment. But in the short term, it sure is fun! In that way, Lisp is...sin."

    Forego the demon temptations of Scheme! Use Perl.

    Not.


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

    February 03, 2006 4:52 PM

    Is Web 2.0 a Mirage?

    Everyone is talking about Web 2.0 these days. This isn't the sort of buzzword that tends to absorb me, as patterns and refactoring and agile methods did, but as tutorials chair for OOPSLA 2006, I am keen to get a sense of what developers are talking about and interested in learning about these days. Web 2.0 is everywhere, and so I've been reading a bit deeper to see what we should offer, technology-wise, at the conference. But the sociology of the term and its penumbra has been as much intriguing as its technology.

    Christian Sepulveda gave thought to why Web 2.0 had captured mindshare now and how it was different from what we've been doing. His answer to "why now?" centered on the convergence of intellectual supply and demand: "The demand for a user centric web, where sharing, communication and a rich experience is the norm, is intersecting the availability of technology, such as RSS and AJAX, to make it happen."

    How is Web 2.0 different from Web 1.x? It is driven by the demands and needs of real users with real problems. So much of the previous web boom, he feels, was driven by a "build it and they will come" mentality.

    Of course, that mentality worked for a lot of ideas that took root back in the old days -- even the 20th century! -- and now have matured. Wikis and blogs are only two such ideas.

    Paul Graham took a somewhat more dispassionate position on Web 2.0, which isn't surprising given his general outlook on the world and, more relevant here, his own experiences doing cool web stuff back before the "availability of technology, such as RSS and AJAX, to make it happen." Here's my precis of his article, consisting of its first and last paragraphs:

    Does "Web 2.0" mean anything? Till recently I thought it didn't, but the truth turns out to be more complicated. Originally, yes, it was meaningless. Now it seems to have acquired a meaning. And yet those who dislike the term are probably right, because if it means what I think it does, we don't need it.

    The fact that Google is a "Web 2.0" company shows that, while meaningful, the term is also rather bogus. It's like the word "allopathic." It just means doing things right, and it's a bad sign when you have a special word for that.

    Graham applauds the fact that Ajax now brings the ability to develop sites that take advantage of the web's possibilities to everyday developers. I found his discussion of democracy on the web, exemplified by sites such as del.icio.us, Wikipedia, Reddit, and Digg, to be right on the mark. The original promise of the web was how it could help us share information, but that promise was only the beginning of something bigger. It took guys like Ward Cunningham to show us the way. This sense of democracy extends beyond participants in social conversation to those folks we in software have always called users. It turns out that users get to participate in the conversation, too!

    In the March 2006 issue of Dr Dobb's Journal, editor at large Michael Swaine expressed a more cynical version of Graham's take:

    Web 2.0 is a commemorative coin minted in celebration of the end of the dot-com crash. Like all commemorative coins, it has no actual value.

    So, we should focus our attention on the technologies that buttress the term, but as Graham points out the ideas behind the technologies aren't new; they are just in a new syntax, a new framework, a new language. The software world creates its own troubles when it recycles old ideas in new form, and then complains that the world is changing all the time.

    The cynical view on AJAX itself is expressed with great amusement by Brian Foote in What's New Here is that Nothing is New Here:

    The fascinating thing about Ajax is that it is an amalgam of existing technologies that all date back to the twentieth century. It's what the Web 2.0 crowd might call a mash-up. Only the name is new.

    Of course, all this cynicism doesn't change the fact that today's developers need to learn the current technologies and how to make them play with the rest of their software. So we'll certainly offer the best tutorials we can for the folks who come to OOPSLA'06.

    And, as always, we should be careful not to let our nostalgia for our old tools blind us. For a sanity check on a slightly different topic (though perhaps more similar than the subject indicates), check out this article by Adam Connor.

    Busy, busy, busy.


    Posted by Eugene Wallingford | Permalink | Categories: Software Development

    January 16, 2006 12:46 PM

    Chairing Tutorials for OOPSLA 2006

    OOPSLA 2006 Long Logo

    After chairing the OOPSLA Educators' Symposium in 2004 and 2005, I've been entrusted with chairing the tutorials track at OOPSLA 2006. While this may not seem to have the intellectual cachét of the Educators' Symposium, it carries the responsibility of a major financial effect on the conference. If I had screwed an educators' event, I would have made a few dozen people unhappy. If I screw up the tutorials track, I could cost the conference tens of thousands of dollars!

    The call for tutorial proposals is out, with a deadline of March 18. My committee and I will also be soliciting a few tutorials on topics we really want to see covered and from folks we especially want to present. We'd like to put together a tutorial track that does a great job of helping software practitioners and academics get a handle on the most important topics in software development these days, with an emphasis on OO and related technologies. In marketing terms, I think of it as exciting the folks who already know that OOPSLA is a must-attend conference and attracting new folks who should be attending.

    I'd love to hear what you think we should be thinking about. What are the hottest topics out there, the ones we should all be learning about? Is there something on the horizon that everyone will be talking about in October? I'm thinking not only of the buzzwords that define the industry these days, but also of topics that developers really need to take their work to another level.

    Who are the best presenters out there, the ones we should be inviting to present? I'm thinking not only of the Big Names but also of those folks who simply do an outstanding job teaching technical content to professionals. We've all probably attended tutorials where we left room thinking, "Wow, that was good. Who was that guy?"

    One idea we are considering this year is to offer tutorials that help people prepare for certifications in areas such as Java and MSCD. Do you think that folks could benefit from tutorials of this sort, or is it an example trying to do too much?

    Trying to keep a great conference fresh and exciting requires a mix of old ideas and new. It's a lot like revising a good course... only in front of many more eyes!


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

    December 28, 2005 10:31 PM

    Agile as Students, but Not Always as Programmers

    I've noticed an interesting disconnect between student behavior when in the role of student and when in the role of software developer.

    When they are in the role of developer, students often fight the idea of XP's small steps: breaking tasks into small, estimable steps, writing a test for each small step, and then making sure the code passes the test before thinking about the next step. They want to think ahead, trust their experience and "intuition", write a lot of code -- and only then compile, run, and test the code. The testing is usually sloppy or, more charitably, incomplete -- at least in part because they are champing at the bit to move on to more code.

    Is this merely a matter of habit they have developed in past CS courses? Or have their years in the K-12 educational system encouraged them to rush headlong into every problem? Perhaps it is our natural human state.

    ... but when in the role of student, students tend behave much differently. They want feedback -- now. When they turn in an assignment, they want the graded result as soon as possible.

    I used to have a serious Grading Avoidance Problem, and all my students disliked it. Students who were otherwise quite happy with my course became cranky when I fell behind in returning assignments. Students who were unhappy with the course for other reasons, well, they became downright hostile.

    I'm mostly over this problem now, though I have to be alert not to backslide. Like a recovering addict, I have to face each day anew with resolve and humility. But I have a colleague for whom this issue is still a major problem, and it creates difficulties for him with his students.

    I can't blame students for wanting graded items back quickly. Those grades are the most reliable way they have of knowing where they stand in the course. Students can use this feedback to make all sorts of decisions about how and how much to study. (I do wish that more students paid more attention to the substantive feedback on their assignments and tried to use that information to improve their technique, to guide decisions about what to study.)

    So: students like frequent feedback to guide their studies.

    Many students also seem to prefer small, discrete, and detailed tasks to work on. This is especially true of students who are just learning to program, but I also see it in juniors or seniors. Many of these upper-division students do not seem to have developed confidence in their ability to solve even medium-sized problems. But when they are given a set of steps that has already been decomposed and ordered, they feel confidence enough to get the job done. They are industrious workers.

    Confessions of a Community College Dean captured my feeling about this feature of today's students when it said, "As a student, I would have been insulted by this approach. But they aren't me." I myself enjoy tackling big problems, bringing order to an unruly mass of competing concerns. Had I always been spoon-fed toy problems already broken into nearly trivial pieces, I wonder if I would have enjoyed computer science as much. I suspect I might have because, like many people who are attracted to CS, I like to create my own problems!

    So: students like to work on small, well-developed tasks whose boundaries they understand well. This, too, helps students focus their study.

    My net acquaintance Chad Orzel, a physicist at Union College, speculates on why students prefer to work in this way. The conventional wisdom is that working on many small, discrete tasks encourages them to keep up with their reading. But I think he is right when he takes this diagnosis one step further: This style of course helps students to compensate for poor time management skills. Larger, less well-defined units require students to figure out what the subtasks are, estimate how long each will take, and then actually do them all in a timely fashion. By structuring our courses as a set of smaller, discrete tasks, we do much of the preparatory work for our students. When students are first learning, this is good, but as they grow (or should be growing) we are merely reinforcing bad habits.

    It seems that we professors are enablers in a system of codependency. :-)

    Even in this regard, the relationship between student as software developer and student as student holds. As I have written before, software methodologies are self-help systems. Perhaps so are the ways we structure problems and lectures for our students.

    Once again, I can't blame students for preferring to work on small, discrete, well-defined tasks. Most people work better under these circumstances. Even those of us who love the challenge of tackling big problems usually succeed by taming the problem's complexity, reducing it to a system of smaller, independent, interacting components. That's what design is.

    Students need to learn how to design, too. When students are getting started, professors need to scaffold their work by doing much of the design for them. Then, as students increase in knowledge and skill, we need to pull the scaffolding away slowly and let students do more and more of their own design. It's easy for professors to fall into the habit of finely specifying student tasks. But in doing this thinking for them, we deny them the essential experience of decomposing tasks for themselves.

    Maybe we can leverage the agile-facing side of student behavior in helping them to develop agile habits as software developers. People aren't always able to change their behavior in one arena when they come to see that it is inconsistent with their behavior in another; we aren't wired that way. But knowing ourselves a little better is a good thing, and creates one more opportunity for our mind to grow.

    (I doubt going the other way would work very well. But it might take away some of the pressure to grade work quickly!)


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

    December 21, 2005 5:07 PM

    Experiments in Art and Software

    Double Planet, by Pyracantha

    Electron Blue recently wrote about some of her experiments in art. As an amateur student of physics, she knows that these experiments are different the experiments that scientists most often perform. She doesn't always start with a "hypothesis", and when she gets done it can be difficult to tell if the experiment was a "success" or not. Her experiments are opportunities to try ideas, to see whether a new technique works out. Sometimes, that's easy to see, as when the paint of a base image dries with a grainy texture that doesn't fit the image or her next stage. Other times, it comes down to her judgment about balance or harmony.

    This is quite unlike many science experiments, but I think it has more in common with science than may at first appear. And I think it is very much like what programmers and software developers do all the time.

    Many scientific advances have resulted from what amounts to "trying things out", even without a fixed goal in mind. On my office wall, I have a wonderful little news brief called "Don't leave research to chance", taken from some Michigan State publication in the early 1990s. The article is about some work by Robert Root-Bernstein, an MSU science professor who in the 1980s spent time as a MacArthur Prize fellow studying creativity in the sciences. In particular, it lists ten ways to increase one's chances of serendipitously encountering valuable new ideas. Many of these are strict matters of technique, such as removing background "noise" that everyone else accepts or varying experimental conditions or control groups more widely than usual. But others fit the art experiment mold, such as running a reaction backward, amplifying a side reaction, or doing something else "unthinkable" just to see what happens. The world of science isn't always as neat as it appears from the outside.

    And certainly we software developers explore and play in a way that an artist would recognize -- at least we do when we have the time and freedom to do so. When I am learning a new technique or language or framework, I frequently invoke the Three Bears Pattern that I first learned from Kent Beck via one of the earliest pedagogical patterns workshops. One of the instantiations of this pattern is to use the new idea everywhere, as often and as much as you can. By ignoring boundaries, conventional wisdom, and pat textbook descriptions of when the technique is useful, the developer really learns the technique's strengths and weaknesses.

    I have a directory called software/playground/ where I visit when I just want to try something out. This folder is a living museum of some of the experiments I've tried. Some are as mundane as learning some hidden feature of Java interfaces, while others are more ambitious attempts to see just how far I can take the Model-View-Controller pattern before the resulting pain exceeds the benefits. Just opportunities to try an idea, to see how a new technique works out.

    My own experience is filled with many other examples. A grad student and I learned pair programming by giving it a whirl for a while to see how it felt. And just a couple of weeks ago, on the plane to Portland for the OOPSLA 2006 fall planning meeting, I whipped up a native Ook! interpreter in Scheme -- just because. (There is still a bug in it somewhere... )

    Finally, I suspect that web designers experiment in much the way that artists do when they have ideas about layout, design, and usability. The best way to evaluate the idea is often to implement it and see what real users think! This even fits Electron Blue's ultimate test of her experiments: How do people react to the work? Do they like it enough to buy it? Software developers know all about this, or should.

    One of the things I love most about programming is that I have the power to write the code -- to make my ideas come alive, to watch them in animated bits on the screen, to watch them interacting with other people's data and ideas.

    As different as artists and scientists and software developers are, we all have some things in common, and playful experimentation is one.


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

    December 03, 2005 10:33 PM

    A Milestone for Our Student Population

    I teach at a "comprehensive university", one of those primarily undergraduate institutions that falls outside of the Research I classification whose schools dominate the mind share of the computer science world. After graduation, most of our students become software practitioners at companies in Iowa and the midwestern U.S.

    Last spring, I was excited when one of my M.S. students became the first student at our university to receive a job offer from Google. I may not have been more excited than he was, but then again maybe I was... His thesis presented some novel work on algorithms for automatic route planning of snow removal operations, an important topic for road departments in my part of the world, and Google found him a promising developer for Google Maps. As an advisor and faculty member, I was filled with pride -- perhaps a false pride. Look at this validation of my work!

    Imagine my disappointment when, for a variety of personal and pragmatic reasons, my student turned Google down. I sympathized with his difficult choice, but where's the caché for me in "I was the advisor of a student who almost worked for Google"? What about my needs?

    Today my excitement was renewed when I found that a former undergraduate student of mine has accepted an offer from ThoughtWorks. In the software world, ThoughtWorks is known as one of the cooler consulting firms out there. Like Google, it seems to hire up lots of the interesting folks, especially in the OO and agile circles I frequent.

    Chris approached Thoughtworks through its ThoughtWorks University program, aimed at attracting promising recent graduates. He is just the sort of student that programs like this seek: a guy who has demonstrated potential in classwork and research, even though he doesn't come from a Big-Name Institution. His undergraduate research project on the construction of zoomable user interfaces won the award for undergraduate scientific research at our university, an award that usually goes to a student in the hard sciences.

    Universities like ours are a relatively untapped resource for advanced technology companies. Our best students are as strong as the best students anywhere. The only problem is that many of them don't have a big enough vision of what they can accomplish in the world. Turning their vision outward, toward entrepreneurial opportunities whether in start-ups or established firms, is the key. It's one of my major goals for our department over the next three years.

    I can take some pride in knowing that my courses in object-oriented programming and agile software development probably helped this student attract some attention from the folks at ThoughtWorks, but I know that it's these students themselves who make opportunities for themselves. As an educator, my job is to help them to see just how big the world of ideas and opportunities really is.


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

    December 01, 2005 7:39 PM

    Cardinality -- or Absolute Value?

    My friend Kris Anderson sent e-mail in response to my entry on I = k|P|. Here's part of what he said:

    So then, I got to thinking about the variable "|P|" in your equation. Absolute value? As I thought about it, Aerosmith's "Dream On" started playing in my head... "Live and learn from fools and from sages..." 'Fools' represent negative values and 'Sages' represent positive values. And since the lesson one can learn from either is of equal value, that's why 'P' must be '|P|'. Very cool.

    As I told him, Now that is cool. When I wrote my message, by |P| I meant the cardinality of the set P. Kris took P to mean not a set but the value of some interaction, either positive or negative. The ambiguous |P| then can indicate that we learn something of value from both positive influences and negative influences, like positive and negative examples in induction. I think that I'll stick with my original intention and leave credit for this re-interpretation to Kris.

    And who knew that anyone would read my entry and make a connection to Aerosmith? Different people, different familiar ideas, different connections. That reminds of something Ward Cunningham said at OOPSLA 2005.

    I learn so much from other folks reading what I write -- yet another example of the point of the article.


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

    November 28, 2005 7:22 PM

    A Formula for Intelligence

    It occurred to me today that my intelligence on any given day is roughly proportional to the number of people I talk to that day:

    I = k|P|

    This is true when I do department head stuff. The more people I get information from, the more people I share ideas with and get feedback from... the more I know, and the better I can do my job.

    It is true when I teach. When I talk to other instructors, I learn from them, both by hearing their ideas and by expressing my ideas verbally to them. When I talk to students about our classes, whether they are in my class or not, I learn a little bit about what works, what doesn't, and what makes students tick.

    It is true when I program. The agile software methods institutionalized this in the form of high degree of interaction among developers. XP raises it to the level of Standard Practice in the form of pair programming. Programmers who refuse to try pairing rarely understand what they are missing.

    The value of k depends on a lot of factors, some of which are within my daily control and some of which are in my control only over longer time horizons. On a daily basis, I can seek out the best folks possible on campus and in my circle of professional colleagues available only by e-mail. Over longer time periods, I can choose the conferences I should attend, the academic communities I can participate in, and even where I want to be employed.

    We all know the adages about hiring the smartest employees one can, about being the least accomplished person on the team, and so on. This is why: it increases the value of your k!


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

    November 23, 2005 1:46 PM

    This and That, from the Home Front

    The daily grind of the department office has descended upon me the last couple of weeks, which with the exception of two enjoyable talks (described here and here) have left me with little time to think in the way that academics are sometimes privileged. Now comes a short break full of time at home with family.

    Here are a few things that have crossed my path of late:

    • Belated "Happy Birthday" to GIMP, which turned 10 on Monday, November 21, 2005. There is a lot of great open-source software out there, much of which is older than GIMP, but there's something special to me about this open-source program for image manipulation. Most of the pros use Photoshop, but GIMP is an outstanding program for a non-trivial task that shows how far an open-source community can take us. Check out the original GIMP announcement over at Google Groups.

    • Then there is this recently renamed oldie but goodie on grounded proofs. My daughters are at the ages where they can appreciate the beauty of math, but their grade-school courses can do only so much. Teaching them bits and pieces of math and science at home, on top of their regular work, is fun but challenging.

      The great thing about explaining something to a non-expert is that you have to actually understand the topic.

      Content and method both matter. Don't let either the education college folks or the "cover all the material" lecturers from the disciplines tell you otherwise.

    • Very cool: an on-line version of John Von Neumann's Theory of Self-Reproducing Automata.

    • Finally, something my students can appreciate as well as I:

      If schedule is more important than accuracy, then I can always be on time.

      Courtesy of Uncle Bob, though I disagree with his assumption that double-entry bookkeeping is an essential practice of modern accounting. (I do not disagree with the point he makes about test-driven development!) Then again, most accountants hold double-entry bookkeeping in nearly religious esteem, and I've had to disagree with them, too. But one of my closest advisors as a graduate student, Bill McCarthy, is an accountant with whom I can agree on this issue!


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

    November 15, 2005 8:51 PM

    Popularizing Science through Writing and Teaching

    I have an interest in writing, both in general as a means for communication and in particular as it relates to the process of programming. So I headed over to the Earth Science department yesterday for a talk on popular science writing called "Words, Maps, Rocks: One Geologist's Path". The speaker was Marcia Bjornerud of Lawrence University, who recently published the popular geology book Reading the Rocks: The Autobiography of the Earth. The Earth Science faculty is using Reading the Rocks as reader in one of their courses, and they asked Dr. Bjornerud to speak on how she came to be a geologist and a popularizer of science.

    Bjornerud took a roundabout way into science. As a child, she had no desire to be a scientist. Her first loves were words and maps. She loved the history of words, tracing the etymology of cool words back to their origin in European languages, then Latin or Greek, and ultimately back to the source of their roots. The history of a word was like a map through time, and the word itself was this rich structure of now and then. She also loved real maps and delighted in the political, geographical, and temporal markings that populated them. Bjornerud told an engaging story about a day in grade school when snow created a vacation day. She remembers studying the time zones on the map and learning that at least two places had no official time zone: Antarctica and Svalborg, Norway.

    These reminiscences probably strike a chord in many scientists. I know that I have spent many hours poring over maps, just looking at cities and open spaces and geopolitical divisions, populations and latitudes and relative sizes. I remember passing time in an undergraduate marketing class by studying a large wall map of the US and first realizing just how much bigger Iowa (a state I had never visited but would one day call home) was than my home state of Indiana (the smallest state west of the Appalachian Mountains!) I especially love looking at maps of the same place over time, say, a map of the US in 1500, 1650, 1750, 1800, and so on. Cities grow and die; population moves inexorably into the available space, occasionally slowing at natural impediments but eventually triumphing. And words -- well, words were why I was at this talk in the first place.

    Bjornerud loved math in high school and took physics at the suggestion of friends who pointed out that the calculus had been invented in large part in order to create modern physics. She loved the math but hated the physics course; it was taught by someone with no training in the area who acknowledged his own inability to teach the course well.

    It wasn't until she took an introductory college geology course that science clicked for her. At first she was drawn to the words: esker, alluvium, pahoehoe, ... But soon she felt drawn to what the words name. Those concepts were interesting in their own right, and told their own story of the earth. She was hooked.

    We scientists can often relate to this story. It may apply to us; some of us were drawn to scientific ideas young. But we certainly see it in our friends and family members and people we meet. They are interested in nature, in how the world works, but they "don't like science". Why? Where do our schools go wrong? Where do we as scientists go wrong? The schools are a big issue, but I will claim that we as scientists contribute to the problem by not doing a good job at all of communicating to the public why we are in science. We don't share the thrill of doing science.

    A few years ago, Bjornerud decided to devote some of her professional energy to systematic public outreach, from teaching Elderhostel classes to working with grade schoolers, from writing short essays for consumption by the lay public to her book, which tells the story of the earth through its geological record.

    To write for the public, scientists usually have to choose a plot device to make technical ideas accessible to non-scientists. (We agile software developers might think of this as the much-maligned metaphor from XP.)

    Bjornerud used two themes to organize her book. The central theme is "rocks as text", reading rocks like manuscripts to reveal the hidden history of the earth. More specifically, she treats a rock as a palimpsest, a parchment on which a text was written and then scraped off, to be written on again. What a wonderful literary metaphor! It can captivate readers in a day when the intrigue of forensic science permeates popular culture.

    Her second theme, polarities, aims more at the micro-structure of her presentation. She had as an ulterior motive, to challenge the modern tendency to see dichotomy everywhere. The world is really a tangled mix of competing concepts in tension. Among the polarities Bjornerud explores are innovation versus conservation (sound familiar?) and strength versus weakness.

    Related to this motive is a desire -- a need -- to instill in the media and the public at larger an appetite for subtlety. People need to know that they can and sometimes must hold two competing ideas in their minds simultaneously. Science is a halting journey toward always-tentative conclusions.

    These themes transfer well to the world of software. The tension between competing forces is a central theme driving the literature of software patterns. Focusing on a dichotomy usually leads to a sub-optimal program; a pattern that resolves the dichotomy can improve it. And the notion of "program as text" is a recurring idea. I've written occasionally about the value in having students read programs as they learn to write them, and I'm certainly not the first person to suggest this. For example, Owen Astrachan once wrote quite a bit on apprenticeship learning through reading master code (see, for example, this SIGCSE paper). Recently, Grady Booch blogged On Writing, in which he suggested "a technical course in selected readings of software source code".

    Bjornerud talked a bit about the process of writing, revising, finding a publisher, and marketing a book. Only one idea stood out for me here... Her publisher proposed a book cover that used a photo of the Grand Canyon. But Bjornerud didn't want Grand Canyon on her cover; the Grand Canyon is a visual cliche, particularly in the world of rocks. And a visual cliche detracts from the wonder of doing geology; readers tune out when they see yet another picture of the Canyon. We are all taught to avoid linguistic cliches like the plague, but how many of us think about cliches in our other media? This seemed like an important insight.

    Which programs are the cliches of software education? "Hello, World", certainly, but it is so cliche that it has crossed over into the realm of essential kitsch. Even folks pitching über-modern Ruby show us puts "Hello, World." Bank account. Sigh, but it's so convenient; I used it today in a lecture on closures in Scheme. In the intro Java world, Ball World is the new cliche. These trite examples provide a comfortable way to share a new idea, but they also risk losing readers whose minds switch off when they see yet another boring example they've seen before.

    In the question-and-answer session that followed the talk, Bjornerud offered some partial explanations for where we go wrong teaching science in school. Many of us start with the premise that science is inherently interesting, so what's the problem?

    • Many science teachers don't like or even know science. They have never really done science and felt its beauty in their bones.

      This is one reason that, all other things being equal, an active scholar in a discipline will make a better teacher than someone else. It's also one of the reasons I favor schools of education that require majors in the content area to be taught (Michigan State) or that at least teach the science education program out of the content discipline's college (math and science education at UNI).

    • We tend explain the magic away in a pedantic way. We should let students discover ideas! If we tell students "this is all there is to it", we hide the beauty we ourselves see.

    • Bjornerud stressed the need for us to help students make a personal connection between science and their lives. She even admitted that we might help our students make a spiritual connection to science.

    • Finally, she suggested that we consider the "aesthetic" of our classrooms. A science room should be a good place to be, a fun place to engage ideas. I think we can take this one step further, to the aesthetic of our instructional materials -- our code, our lecture notes, our handouts and slides.

    The thought I had as I left the lecture is that too often we don't teach science; we teach about science. At that point, science becomes a list of facts and names, not the ideas that underlie them. (We can probably say the same thing about history and literature in school, too.)

    Finally, we talked a bit about learning. Can children learn about science? Certainly! Children learn by repetition, by seeing ideas over and over again at increasing degrees of subtlety as their cognitive maturity and knowledge level grow. Alan Kay has often said the same thing about children and language. He uses this idea as a motivation for a programming language like Smalltalk, which enables the learner to work in the same language as masters and grow in understanding while unfolding more of the language as she goes. His groups work on eToys seeks to extend the analogy to even younger children.

    Most college students and professionals learn in this way, too. See the Spiral pedagogical pattern for an example of this idea. Bjornerud tentatively offered that any topic -- even string theory!?, can be learned at almost any level. There may be some limits to what we can teach young children, and even college students, based on their level of cognitive development, their ability to handle abstractions. But for most topics most of the time -- and certainly for the basic ideas of science and math -- we can introduce even children to the topic in a way they can appreciate. We just have to find the right way to pitch the idea.

    This reminds me, too, of Owen Astrachan and his work on apprenticeship mentioned above. Owen has since backed off a bit from his claim that students should read master code, but not from the idea of reading code itself. When he tried his apprenticeship through reading master code, he found that students generally didn't "get it". The problem was that they didn't yet have the tools to appreciate the code's structures, its conventions and its exceptions, its patterns. They need to read code that is closer to their own level of programming. Students need to grow into an appreciation of master code.

    Talks like this end up touching on many disparate issues. But a common thread runs through Bjornerud's message. Science is exciting, and we scientists have a responsibility to share this with the world. We must do so in how we teach our students, and in how we teach the teachers of our children. We must do so by writing for the public, engaging current issues and helping the citizenry to understand how science and technology are changing the world in which we live, and by helping others who write for the public to appreciate the subtleties of science and to share the same through their writing.

    I concur. But it's a tall order for a busy scientist and academic. We have to choose to make time to meet this responsibility, or we won't. For me, one of my primary distractions is my own curiosity -- that which makes us a scientist in the first place drives us to push farther and deeper, to devote our energies to the science and not to the popularizing of it. Perhaps we are doomed to the G. H. Hardy's conclusion in his wonderful yet sad A Mathematician's Apology: Only after a great mind has outlived its ability to contribute to the state of our collective knowledge can -- should? will? -- it turn to explaining. (If you haven't read this book, do so soon! It's a quick read, small and compact, and it really is both wonderful and sad.)

    But I do not think we are so doomed. Good scientists can do both. It's a matter of priorities and choice.

    And, as in all things, writing matters. Writing well can succeed where other writing fails.


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

    November 09, 2005 6:54 PM

    More Visibility from the Blog

    Back in March, I was contacted by my local paper for an article on local bloggers. That was, I think, the first time that someone outside my expected audience had contacted me about my blog.

    Last week, I was contacted by a gentleman named Alex Gofman, who is CTO for Moskowitz Jacobs Inc. and is writing a book on the marketing techniques of his company's founder, Howard Moskowitz. If you have been reading this blog for long, you may remember a nearly year-old article I wrote entitled What Does the iPod have in Common with Prego Spaghetti Sauce?, in which I discussed some ideas on design, style, and creativity. My thoughts there were launched by articles I'd read from Paul Graham and Malcolm Gladwell. The Gladwell piece had quoted Moskowitz, and I quoted Gladwell quoting Moskowitz.

    Mr. Gofman apparently had googled on Moskowitz's name and come across my blog as a result. He was intrigued by the connections I made between the technique used to revive Prego and the design ideas of Steve Jobs, Paul Graham, agile software methods, and Art and Fear. He contacted me by e-mail to see if I was willing to chat with him at greater depth on these ideas, and we had a nice 45-minute conversation this morning.

    It was an interesting experience talking about an essay I wrote a year ago. First of all, I had to go back and read the piece myself. The ideas I wrote about then have been internalized, but I couldn't remember anything particular I'd said then. Then, during the interview, Mr. Gofman asked me about an earlier blog entry I'd written on the rooster story from Art and Fear, and I had to scroll down to remember that piece!

    Our conversation explored the edges of my thoughts, where one can find seeming inconsistencies. For example, the artist in the rooster story did many iterations but showed only his final product. That differs from what Graham and XP suggest; is it an improvement or a step backward? Can a great designer like Jobs create a new and masterful design out of whole cloth, or does he need to go through a phase of generating prototyping to develop the idea?

    In the years since the Prego experience reported by Gladwell, Moskowitz has apparently gone away from using trained testers and toward many iterations with real folks. He still believes strongly in generating many ideas -- 50, not 5 -- as a means to explore the search space of possible products. Mr. Gofman referred to their technique as "adaptive experimentation". In spirit, it still sounds a lot like what XP and other agile methods encourages.

    I am reluctant to say that something can't happen. I can imagine a visionary in the mold of Jobs whose sense of style, taste, and the market enable him to see new ideas for products that help people to feel desires they didn't know they had. (And not in the superficial impulse sense that folks associate with modern marketing.) But I wouldn't want to stake my future or my company on me or most anyone I know being able to do that.

    The advantage of the agile methods, of the techniques promoted in Art and Fear, is that they give mere mortals such as me a chance to create good products. Small steps, continuous feedback from the user, and constant refactoring make it possible for me to try working software out and learn from my customers what they really want. I may not be able to conceive the iPod, but I can try 45 kinds of sauce to see which one strikes the subconscious fancy of a spaghetti eater.

    This approach to creating has at least two other benefits. First, it allows me to get better at what I do. Through practice, I hone my skills and learn my tools. Though sheer dent of repetition and coming into contact with many, many creations, I develop a sense of what is good, good enough, and bad. Second, just by volume I increase my chances of creating a masterpiece every now and then. No one may have seen all of my scratch work, but you can be sure that I will show off my occasional masterpiece. (I'm still waiting to create one...)

    We should keep in mind that even visionary designers like Jobs fail, too -- whether by creating a product ahead of its time, market- or technology-wise too soon, or by simply being wrong. They key to a guy like Jobs is that he keeps coming back, having learned from his experience and trying again.

    I see this mentality as essential to my work as a programmer, as a teacher, and now as an administrator. My best bet is to try many things, trust my "customer" (whether user, student, or faculty colleague) enough to let them see my work, and try to get better as I go on.

    In part as a result of our conversation this morning, Mr. Gofman -- who is a software developer trained as a computer engineer -- decided to proposing adding a chapter to his book dealing with software development as a domain for adaptive experimentation. I learned that he is an XP aficionado who understands it well enough to know that it has limits. This chapter could be an interesting short work on agile methods from a different angle. I look forward to seeing what may result.

    As Mr. Gofman and I chatted this morning, I kept thinking about how fear and creativity had come up a few times at OOPSLA this year, for example, here and here. But I didn't have a good enough reason to tell him, "You should read every article on my blog." :-) In any case, I wish him luck. If you happen to read the book, be on the look out for a quote from yours truly.


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

    November 08, 2005 3:00 PM

    An Index to the OOPSLA Diaries

    I have now published the last of my entries intended to describe the goings-on at OOPSLA 2005. As you can see from both the number and the length of entries I wrote, the conference provided a lot of worthwhile events and stimulated a fair amount of thinking. Given the number of entries I wrote, and the fact that I wrote about single days over several different entries and perhaps several weeks, I thought that some readers might appreciate a better-organized index into my notes. Here it is.

    Of course, many other folks have blogged on the OOPSLA'05 experience, and my own notes are necessarily limited by my ability to be in only one place at a time and my own limited insight. I suggest that you read far and wide to get a more complete picture. First stop is the OOPSLA 2005 wiki. Follow the link to "Blogs following OOPSLA" and the conference broadsheet, the Post-Obvious Double Dispatch. In particular, be sure to check out Brian Foote's excellent color commentary, especially his insightful take on the software devolution in evidence at this year's conference.

    Now, for the index:

    Day 1

    Day 2

    Day 3

    Day 4

    Day 5

    This and That

    I hope that this helps folks navigate my various meanderings on what was a very satisfying OOPSLA.

    Finally, thanks to all of you who have sent me notes to comment on this postings. I appreciate the details you provide and the questions you ask...

    Now, get ready for OOPSLA 2006.


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

    November 07, 2005 7:30 PM

    OOPSLA Day 2: A Panel of the Direction of CS Education

    The final item on the Educators Symposium program this year was a panel discussion on the future of computer science education. It was called Are We Doomed? Reframing the Discussion, in partial gest following last SIGCSE's panel debate Resolved: "Objects Early" Has Failed. After that session, Owen Astrachan commented, "We're doomed." What did he mean by this? Despite our own declarations that this is The Age of Information and that computer science is a fundamental discipline for helping the world to navigate and use the massive amount of information now being collected, we still teach CS courses in essentially the same way we always have. We still use toy examples in toy domains that don't really matter to anyone, least of all of students. We still teach our introductory courses as 100% old-style programming, with barely a nod to users, let alone to the fact that sophisticated consumers of computing grow increasingly independent of us and our inward focus.

    Owen Astrachan

    This summer, Owen said it this way:

    We have the human genome project, we have Google, we have social networks, we have contributions to many disciplines, and our own discipline, but we argue amongst ourselves about whether emacs is better than vi, Eclipse better than IDEA, C++ better than Java or Scheme, or what objects-first really means.

    I'm sorry, but if we don't change what we talk about amongst ourselves, we are doomed to a niche market while the biologists, the economists, the political scientists, etc., start teaching there own computational/modeling/programming/informatics courses. Nearly everyone turns to math for calculus, nearly everyone turns to math/stats for statistics. These are nearly universally acknowledged as basic and foundational for *lots* of disciplines. In the age of information nearly no discipline at a large scale requires computer science, certainly not programming as we teach it.

    Owen isn't as pessimistic as the provocative "We're doomed" sounds; he simply wants to cause us to think about this sea change and begin to make a change ourselves.

    I decided that this would make a great closing for my second Educators Symposium. Last year, my first symposium opened with Alan Kay challenging us all to set a higher bar for ourselves -- in computer science, and in computer science education. This year, my second symposium would close with a challenge to reinvent what we do as a discipline.

    As in so many things, the panel did not turn out quite the way I had planned. First of all, Owen wasn't able to be at OOPSLA after all, so we were without our intellectual driving force. Then, when the panel went live, discussion on the panel went in a different direction than I had planned. But it had its good points nonetheless. The panel consisted of Robert Biddle, Alistair Cockburn, Brian Marick, and Alan O'Callaghan. I owe special thanks to Alistair and Alan, who joined us on relatively short notice.

    As moderator, I had hoped to pen a wonderfully humorous introduction for for each of the panelists, to loosen things up before we dropped the gloves and got serious about changing the face of computer science. Perhaps I should have commissioned a master to ghostwrite, for in my own merely mortal hands my dream went unfulfilled. I did have a couple of good lines to use. I planned to introduce Robert as the post-modern conscience of the Educators Symposium, maybe with a visual bow to one of his previous Onward! presentations. For Brian, my tag line was to be "the panelist most likely to quote Heidegger -- and make you love him anyway". But I came up short for Alistair and Alan. Alistair's paper on software development as cooperative game playing was one possible source of inspiration. For Alan, all I could think was, "This guy has a higher depth/words ratio than most everyone I know". In the end, I played it straight and we got down to business rather quickly.

    I won't try to report the whole panel discussion, as I got sucked into it and didn't take elaborate notes. In general, rather than focusing on how CS is being reinvented and how CS education ought to be reinvented, it took a turn toward metaphors for CS education. I will describe what was for me the highlight of the session and then add a couple of key points I remember.

    Robert Biddle

    The highlight for me was Robert's presentation, titled "Deprogramming Programming". It drew heavily on the themes that he and James Noble have been pitching at recent Onward! performances, in particular that much of what we take as accepted wisdom in software development these days is created by us and is, all too often, just wrong.

    He started with a quote from Rem Koolhaus and Bruce Mau's "S, M, L, XL":

    Sous le pavé, la plage.
    (Under the paving stone, the beach.)

    There is something beneath what we have built as a discipline. We do not program only our computers... We've programmed ourselves, in many wrong ways, and it's time to undo the program.

    Narcissus

    The idea that there is a software crisis is a fraud. There isn't one now, and there wasn't one when the term 'software engineering' was coined and became a seemingly unavoidable part of our collective psyche. Robert pointed out that in Greek mythology Narcissus fell in love not with himself but with his reflection. He believes that the field of software engineering has done the same, fallen in love with an image of itself that it has created. We in CS education are often guilty of the same offense.

    Robert then boldly asserted that he loves his job as a teacher of computing and software development. If we look under the pavement, we will see that we developed a lot of useful, effective techniques for teaching students to build software: study groups, role play, and especially case studios and studios. I have written before about my own strong belief in the value of case studios and software studios, so at this point I nearly applauded.

    Finally:

    The ultimate goal of computer science is the program.

    This quote is in someways antithetical to the idea Owen and I were basing the panel on (which is one reason I wanted Robert to be on the panel!), but it also captures what many folks believe about computing. I am one of them.

    That certainly doesn't do justice to the stark imagery and text that constituted Robert's slides, nor to the distinctive verbal oratory that Robert delivers. But it does capture some of the ideas that stuck with me.

    The rest of the panel presentations were good, and the discussion afterward ranged far and wide, with a recurring them of how we might adopt a different model for teaching software development. Here are a few points that stood out:

    • Brian offered two of ideas of interest: demonstration a lá the famed on-line demo of using Ruby on Rails to build a blog engine fifteen minutes, and education patterned on that his wife received and dishes out as a doctor of veterinary medicine.

    • Alan said that we in CS tend to teach the anatomy of a language, not how to use a language. He and I have discussed this idea before, and we both believe that patterns -- elementary or otherwise -- are a key to changing this tendency.

    • Dave West chimed in from the audience with a new statement of computer science's effect on the world reminiscent of his morning presentation: "We are redefining the world in which all of us work and live."

    • Two ideas that should be a bigger part of how we teach software development are a focus on useful things and study of existing work. Various people have been using these ideas in various forms for a while now, and we have uncovered some of the problems hidden behind their promise. For example, students aren't often ready to read programs that are *too* good very quickly; they simply don't appreciate their goodness until they have developed a better sense of taste. But if we framed more of our teaching efforts around these ideas and worked to compensate for their shortcomings, we would probably be better off than doing The Same Old Thing.

    All in all, the panel did not go where I had intended for it to go. Of course, Big Design Up Front can be that way. Sometimes you have to take into account what your stakeholders want. In my case, the stakeholders were the panelists and the audience, with the audience playing the role of pseudo-customer. Judging from the symposium evaluations, many folks enjoyed the panel, so maybe it worked out all right after all.

    Of course, what I had hoped for the panel was to challenge folks in the audience to feel uneasy about the direction of the discipline, to dare to think Big Thoughts about our discipline. I don't think we accomplished that. There will be more opportunities in the future.


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

    November 05, 2005 2:14 PM

    Beautiful Hacks Live On

    As PragDave recently wrote, the Ruby Extensions Project contains a "absolutely wonderful hack". This hack brought back memories and also reminded me of a similar but more ambitious project going on in the Ruby world.

    First of all, here's the hack... One of Ruby's nice features is its collections' internal iterators. Instead of writing a for-loop to process every item in a collection, you send the collection a map message with a one-argument block as its argument. PragDave's example is to convert all the strings in an array uppercase, and the standard Ruby code is

    names.map { |name| name.upcase }

    The map method applies the block -- effectively a nameless method -- to every item in names.

    This is a very nice feature, but after you program in Ruby you want more... Isn't writing that block more work than I should have to do? Why can't I just pass upcase, which is a one-argument method, as the argument to map? Because upcase isn't a method or a procedure; it's a symbol that names a method.

    As PragDave reports, the Ruby Extensions hack adds a method to the Symbol class that allows Symbols to be coerced to a procedure object at run-time. The result is that we can now write the following:

    names.map(&:upcase)

    That's more succinct and avoids the need to create a new procedure object on the fly.

    Now the memory... I distinctly remember the afternoon I learned the same hack in Smalltalk, back in the summer of 1988. You see, Smalltalk's collections also offer an array of internal iterators that eliminates the need to write most for-loops, and these iterators take blocks as arguments.

    I was just learning Smalltalk and loved this idea -- it was my first exposure to object-oriented programming and the power of blocks, which are like functional programming's higher-order procedures. I was working on some code to sort a collection. In Smalltalk, collections also respond to a sort: message, whose argument is a two-argument block for comparing the values. So, to sort a collection of strings in ascending order, I could write:

    names sort: [ x y | x < y ]

    But soon I wanted more... Why can't I just pass < to sort:? The same reason I can't do it in Ruby: < isn't a block or a method; it is a symbol that names a method.

    While figuring this out, I learned how sort: works. It turns around and sends the block a value:value: message with pairs of values from the collection as the two arguments. Hmm, what if a Symbol could respond to value:value: and do the right thing? I added a one-line method to the Symbol class, and they could:

    value: anObject value: otherObject
          ^anObject perform: self with: otherObject

    (perform: behaves something like Scheme's eval procedure.)

    And now I could write the wonderfully compact

    names sort: <

    I soon added the one-argument form to Symbol, too, and began to write new code with abandon.

    I felt pretty smug at the time, for having created something so beautiful. But I soon learned that I had merely rediscovered a hack that every Smalltalk programmer either reinvents or sees in someone else's code. That didn't diminish the beauty of my idea, but it did extinguish my smugness.

    It turns out that this new hack is not only more compact and more convenient to write, but it runs faster than the block alternative, too. The callback on the symbol doesn't require the creation of a block on the fly, which requires memory allocation and the whole bit.

    Finally, for the more ambitious project... This cool hack points out that Ruby and Smalltalk method names are symbols, and without some coercion they are not evaluated to their method values in ordinary use. What if messages were first-order objects in these languages? If so, then I can writing message sends that take other messages as arguments, thus creating higher-order messages. If you are interested in this idea, check out Nat Pryce's recent efforts to add higher-order messaging to Ruby, if you haven't already seen it. Nat gives a link to the paper that laid the foundation for this idea and steps you through the value of higher-order messages and their implementation in Ruby. It's another absolutely wonderful hack.


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

    November 04, 2005 5:16 PM

    Simplicity and Humility in Start-Ups

    Two of Paul Graham's latest essays, Ideas for Startups and What I Did This Summer, echo ideas about simplicity, exploration, and conventional wisdom that Ward Cunningham talked about in his Educators' Symposium keynote address. Of course, Graham speaks in the context of launching a start-up company, but I don't think he sees all that much difference between that and other forms of exploration and creation.

    Ideas for Startups focuses first on a problem that many people face when trying to come up with a Big Idea: they try to come up with a Big Idea. Instead, Graham suggests asking a question...

    Treating a startup idea as a question changes what you're looking for. If an idea is a blueprint, it has to be right. But if it's a question, it can be wrong, so long as it's wrong in a way that leads to more ideas.

    Humility. Simplicity. Learn something along the way. This is just the message that Ward shared.

    Later, he speaks of how to "do" simplicity...

    Simplicity takes effort -- genius, even. ... It seems that, for the average engineer, more options just means more rope to hang yourself.

    In this regard, Ward offers more hope to the rest of us. Generating a truly great something may require genius; maybe not. But in any case, ordinary people can act in a way that biases their own choices toward simplicity and humility, and in doing so learn a lot and create good programs (or whatever). That's what things like CRC cards, patterns, and XP are all about. I know a lot of people think that XP requires Superhero programmers to succeed, but I know lots of ordinary folks who benefit from the agile mindset. Take small steps, make simple choices where possible, and get better as you go.

    I am not sure whether of how pessimistic Graham really is here about achieving simplicity, but his writing often leaves us thinking he is. But I prefer to read his stuff as "Yeah, I can do that. How can I do that?" and take good lessons from what he writes.

    Then, in "What I Did This Summer", Graham relates his first experience with the Summer Founders Program, bankrolling a bunch of bright, high-energy, ambitious your developers. Some of the lessons his proteges learned this summer are examples of what Ward told us. For example, on learning by doing:

    Another group was worried when they realized they had to rewrite their software from scratch. I told them it would be a bad sign if they didn't. The main function of your initial version is to be rewritten.

    This is an old saw, one I'm surprised that the SFP needed to learn. Then again, we often know something intellectually but, until we experience it, it's not our own yet.

    But I really liked the paragraphs that came next:

    That's why we advise groups to ignore issues like scalability, internationalization, and heavy-duty security at first. I can imagine an advocate of "best practices" saying these ought to be considered from the start. And he'd be right, except that they interfere with the primary function of software in a startup: to be a vehicle for experimenting with its own design. Having to retrofit internationalization or scalability is a pain, certainly. The only bigger pain is not needing to, because your initial version was too big and rigid to evolve into something users wanted.

    I suspect this is another reason startups beat big companies. Startups can be irresponsible and release version 1s that are light enough to evolve. In big companies, all the pressure is in the direction of over-engineering.

    Ward spoke with great feeling about being willing to settle for the incomplete, about ignoring some things you probably shouldn't ignore, about disobeying conventional wisdom -- all in the service of keeping things simple and being able to see patterns and ideas that are obscured by the rules. We are conditioned to think of these behaviors as irresponsible, but they may in fact point us in the most likely direction of success.

    ----

    I also found one really neat idea to think about from reading these papers that is independent of Ward's Cunningham. Graham was talking about doodling and what the intellectual equivalent is, because doodling is such a productive way for visual artists to let their minds wonder. Technical innovators need to let their minds wander so that they can stumble upon newly synthesized ideas, where a common frame of reference is applied to some inappropriate data. This can be the source of analogies that help us to see newly.

    Out of this discussion, his programmer's mind created a programming analogy:

    That's what a metaphor is: a function applied to an argument of the wrong type.

    What a neat idea, both as a general characterization of metaphor and also as a potential source of ideas for programming languages. What might a program gain from the ability to reason about a function applied to invalid arguments? On its face, that's an almost meaningless question, but that's part of Graham's -- and Ward's -- point. What may come from such a thought? I want to think more.

    I don't know that I have any more time than Graham to spend on this particular daydream...


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

    November 04, 2005 8:34 AM

    OOPSLA Day 2: Ward Cunningham on Seeking and Exploiting Simplicity

    Ward Cunningham

    The keynote address for this year's Educators' Symposium was given by Ward Cunningham, one of the software folks I admire most. Of course, he's admired by many folks, including not surprisingly by the folks who organized the Wiki Symposium launched by and collocated with OOPSLA this year. As a result, Ward's keynote to our group had to be moved from its traditional first slot of the day to the slot immediately after lunch. This gave the keynote a different feel, because we all had a morning's worth of activities in which to hear Ward's words. (You can read a summary of Ward's Wiki Symposium keynote, titled "The Crucible of Creativity".)

    I introduced Ward by telling the audience how I first encountered his work. At AAAI 1995 in Montreal, I was discussing some of my ideas on teaching elementary patterns with a colleague from Wales. He said, "I have a book for you to review..." You see, he was one of the editors of the journal Expert Systems, and he had received a book for review that he didn't know what to do with. It was about software patterns, and he figured that I'd be an okay reviewer. He was probably encouraged to think this by the fact that none of his other AI friends seemed to be interested.

    The book was Pattern Languages of Program Design, and it changed my life. I had never been exposed to the nascent software patterns community, and this book introduced me to a lot of ideas and, ultimately, people who have played an important role in my academic work since.

    One of the papers in PLoPD-1 affected me immediately. It was about the CHECKS pattern language, and it was written by Ward Cunningham. These patterns were so simple, so obvious, yet as I read them I learned something about maintaining the integrity of the data in my programs. As I looked for more of Ward's work, I soon learned that what attracted me to CHECKS was a hallmark of Ward's: the ability to recognize simple ideas that offered unexpected depth and to explore that depth, patiently and humbly. So many of Ward's contributions to standard practice have been the result of a similar process: CRC cards, patterns, wiki, extreme programming, test-first design, and FIT among them.

    I asked Ward to keynote the Educators Symposium because I admired his work but because I hoped that he could teach us educators -- especially me -- a little bit of his secret gift. Maybe I could nurture the gift in myself, and maybe even pass on something to my students.

    Ward opened his talk with a reminiscence, too. As an electrical engineering major in college, he learned about Maxwell's equations from a Professor Simpson. The professor taught the equations with passion, and he expected his students to appreciate their beauty. Much of their beauty lay in their simplicity, in how that brought so many important facets together into such a small number of straightforward equations. Professor Simpson also loved the work of Richard Feynman, who himself appreciated simplicity and wrote with humanity about what he learned.

    One of Ward's first slides was The Big Slide, the take-home point of his talk. He characterized his way of working as:

    Ward's big slide: familiar + simplicity -> something new

    Immerse yourself in a pool of ideas. Come to know them. Make them your own. Then look for some humble idea lying around, something that we all understand or might. Play with this idea to see whether it gives rise to something unexpected, some new ability that changes how we see or work with the pool of familiar ideas you are swimming in.

    I have experienced the dangers inherent in looking for a breakthrough idea in the usual ways. When we look for Big Ideas, too often we look for Big Ideas. But they are hard to find. Maybe we can't recognize them from our current vantage point; maybe they are out of scale with the ideas we have right now.

    Ward pointed out another danger: Too often, we look for complete ideas when a simple but incomplete idea will be useful enough. (Sounds like You Aren't Gonna Need It!)

    Sometimes, we reach a useful destination by ignoring things we aren't supposed to ignore. Don't worry about all the things you are supposed to do, like taking your idea through to its logical conclusion right away, or polishing it up so that everyone can see how smart you are. Keep the ideas simple, and develop just what you need to move forward.

    Ward pointed out that one thing we educators do is the antithesis of his approach: the project due date. It forces students to "get done", to polish up the "final version", and to miss opportunities to explore. This is one of the good things behind longer-term projects and undergraduate research -- they allow students more time to explore before packaging everything up in a neat little box.

    How can we honor the simple in what we do? How can we develop patience? How can we develop the ability to recognize the simple idea that offers more?

    Ward mentioned Kary Mullis's Dancing Naked in the Mind Field as a nice description of the mindset that he tries to cultivate. (You may recall my discussion of Mullis's book last year.) Mullis was passionate, and he had an immediate drive to solve a problem that no one thought mattered much. When he showed his idea to his colleagues, they all said, "Yeah, that'd work, but so what?". So Mullis gave in to the prevailing view and put his idea on the shelf for a few months. But he couldn't shake the thought that his simple little not-much of an idea could lead to big things, and eventually he returned to the idea and tinkered a little more... and won a Nobel Prize.

    Extreme Programming grew out of the humble practices of programmers who were trying to learn how to work in the brave new image of Smalltalk. Ward is happy that P creates a work environment that is safe for the kind of exploration he advocates. You explore. When you learn something, you refactor. XP says to do the simplest thing that could possibly work, because you aren't gonna need it.

    Many people have misunderstood this advice to mean do something simplistic, something stupid. But it really means that you don't have to wait until you understand everything before you do anything. You can do useful work by taking small steps. These principles encourage programmers to seriously consider just what is the simplest thing that could possibly work. If you don't understand everything about your domain and your task, at least you can do this simplest thing now, to move forward. When you learn more later, you won't have over-invested in ideas you have to undo. But you will have been making progress in the meantime.

    (I don't think that Ward actually said all of these words. They are my reconstruction of what he taught me during his talk. If I have misrepresented his ideas in any way, the fault is mine.)

    Ward recalled first getting Smalltalk, which he viewed as a "sketchpad for the thinking person to write spike solutions". Have an idea? Try to program it! Everything you need or could want to change is there before you, written in the same language you are using. He and Kent realized that they now had a powerful machine and that they should "program in a powerful way". Whenever in the midst of programming they slowed down, he would ask Kent, "What is the simplest thing that could possibly work?", and they would do that. It got them over the hump, let them regain their power and keep on learning.

    This practice specializes his Big Slide from above to the task of programming:

    Ward's big slide: familiar + small step -> learn something

    Remember: You can't do it all at once. Ride small steps forward.

    This approach to programming did not always follow the most efficient path to a solution, but it always made progress -- and that's more than they could say by trying to stay on the perfect path. The surprise was that the simple thing usually turned out to be all they needed.

    Ward then outlined a few more tips for nurturing simple ideas and practices:

    Practice that which is hard.

    ... rather than avoiding it. Do it every day, not just once. An example from software development is schema evolution. It's too hard to design perfect schema up front, so design them all the time.

    Hang around after the fact.

    After other people have explored an area heavily and the conventional wisdom is that all of the interesting stuff has been done, hang around. Tread in well-worn tracks, looking for opportunities to make easier what is hard. He felt that his work on objects was a good example.

    Connect with lower level abstractions.

    That's the beauty of Smalltalk -- so many levels of abstraction, all written in the same language, all connected in a common way.

    Seek a compact expression.

    In the design of programming languages, we often resist math's greatest strength -- the ability to create compact expressions -- in favor of uniformity. Smalltalk is two to four times more compact than Java, and Ward likes that -- yet he knows that it could be more compact. What would Smalltalk with fewer tokens feel like?

    Reverse prevailing wisdom.

    Think the opposite of what everyone says is the right way, or the only way. You may not completely reverse how you do what you do, but you will be able to think different thoughts. (Deconstruction reaches the technical world!)

    From the audience, Joe Bergin pointed out his personal favorite variant of this wisdom (which, I think, ironically turns Ward's advice back on itself): Take a good idea and do it to the hilt. This is, of course, how Kent Beck initially described XP -- "Turn the knobs up to 10."

    Simplicity is not universal but personal, because it builds upon a person's own pool of familiar ideas. For example, if you don't know mathematics, then you won't be able to avail yourself of the simplicities it offers. (Or want, or know to want to.)

    At this point, Ward ended his formal talk and spent almost an hour demonstrating some of these ideas in the testbed of his current hobby project, the building of simple computers to drive an equally simple little CRT. I can't do justice to all he showed us during this phase of his keynote, but it was remarkable... He created his own assembly language and then built a little simulator for it in Java. He created macros. He played with simple patterns on the screen, and simple patterns in the wiring of his little computer board. He hasn't done anything to completion -- his language and simulator enable him to do only what he has done so far. But that has been good enough to learn some neat ideas about the machines themselves and about the programs he's written.

    While I'm not sure anything concrete came out of this portion of his talk, I could see Ward's joy for exploration and his fondness for simple questions and just-good-enough solutions while playing.

    We probably should all have paid close attention to what Ward was doing because, if the recent past has taught us anything, it is that in five years we will all be doing what Ward is playing with today.


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

    October 31, 2005 7:19 PM

    "Mechanistic"

    In my recent post on Gerry Sussman's talk at OOPSLA, I quoted Gerry Sussman quoting concert pianist James Boyk, and then commented:

    A work of art is a machine with an aesthetic purpose.

    (I am uncomfortable with the impression these quotes give, that artistic expression is mechanistic, though I believe that artistic work depends deeply on craft skills and unromantic practice.)

    Thanks to the wonders of the web, James came across my post and responded with to my parenthetical:

    You may be amused to learn that fear of such comments is the reason I never said this to anyone except my wife, until I said it to Gerry! Nevertheless, my remark is true. It's just that word "machine" that rings dissonant bells for many people.

    I was amused... I mean, I am a computer scientist and an old AI researcher. The idea of a program, a machine, being beautiful or even creating beauty has been one of the key ideas running through my entire professional life. Yet even for me the word "machine" conjured up a sense that devalued art. This was only my initial reaction to Sussman's sentiment, though. I also felt an almost immediate need to mince my discomfort with a disclaimer about the less romantic side of creation, in craft and repetition. I must be conflicted.

    James then explained the intention underlying his use of the mechanistic reference in way that struck close to home for me:

    I find the "machine" idea useful because it leads the musician to look for, and expect to find, understandable structures and processes in works of music. This is productive in itself, and at the same time, it highlights the existence and importance of those elements of the music that are beyond this kind of understanding.

    This is an excellent point, and it sheds light on other domains of creation, including software development. Knowing and applying programming patterns helps programmers both to seek and recognize understandable structures in large programs and to recognize the presence and importance of the code that lies outside of the patterns. This is true even -- especially!? -- for novice programmers, who are just beginning to understand programs and their structure, and the process of reading and writing them. Much of the motivation for work on the use of elementary patterns in instruction, as we try to help learn to comprehend masses of code that at first glance may seem but a jumble but which in fact bear a lot of structure within them. Recognizing code that is and isn't part of recurring structure, and understanding the role both play, is an essential skill for the novice programmer to learn.

    Folks like Gerry Sussman and Dick Gabriel do us all a service by helping us to overcome our discomfort when thinking of machines and beauty. We can learn something about science and about art.

    Thanks to James for following up on my post with his underlying insight!


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

    October 27, 2005 7:56 PM

    OOPSLA Day 5: Grady Booch on Software Architecture Preservation

    Grady Booch, free radical

    Grady Booch refers to himself as an "IBM fellow and free radical". I don't know if 'free radical' part of his job description or only self-appellation, but it certainly fits his roving personality. He is a guy with many deep interests and a passion for exploring new lands.

    His latest passion is Handbook of Software Architecture, a project that many folks thinks is among the most important strategic efforts for the history and future of software development.

    Booch opened his invited talk at OOPSLA by reminding everyone that "classical science advances via the dance between quantitative observation and theoretical construction." The former is deliberate and intentional; the latter is creative and testable. Computer science is full of empirical observation and the construction of theories, but in the world of software we often spend all of time building artifacts and not enough time doing science. We have our share of theories, about process and tools, but much of that work is based on anecdote and personal experience, not the hard, dispassionate data that reflects good empirical work.

    Booch reminisced about a discussion he had with Ralph Johnson at the Computer Museum a few years ago. They did a back-of-envelope calculation that estimated the software industry had produces approximately 1 trillion lines of code in high-level languages since the 1950s -- yet little systematic empirical study had been done of this work. What might we learn from digging through all that code? One thing I feel pretty confident of: we'd find surprises.

    In discussing the legacy of OOPSLA, Booch mentioned one element of the software world launched at OOPSLA that has taken seriously the attempt to understand real systems: the software patterns community, of which Booch was a founding father. He hailed patterns as "the most important contribution of the last 10-12 years" in the software world, and I imagine that his fond evaluation rests largely on patterns community's empirical contribution -- a fundamental concern for the structure of real software in the face of real constraints, not the cleaned up structures and constraints of traditional computer science.

    We have done relatively little introspection into the architecture of large software systems. We have no common language for describing architectures, no discipline that studies software in a historical sense. Occasionally, people publish papers that advance the area -- one that comes to mind immediately is Butler Lampson's Hints for Computer System Design -- but these are individual efforts, or ad hoc group efforts.

    The other thing this brought to my mind was my time in an undergraduate architecture program. After the first-year course, every archie took courses in the History of Housing, in which students learned about existing architecture, both as historical matter and to inform current practice. My friends became immersed in what had been done, and that certainly gave them a context in which to develop their own outlook on design. (As I look at the program's current curriculum, I see that the courses have been renamed History of Architecture, which to me replaces the rich flavor of houses for the more generic 'architecture', even if it more accurately reflects the breadth of the courses.)

    Booch spent a next part of his talk comparing software architecture to civil architecture. I can't do justice to this part of his talk; you should read the growing volume of content on his web site. One of his primary distinctions, though, involved the different levels of understanding we have about the materials we use. The transformation from vision to execution in civil systems is not different in principle from that in software, but we understand more about the physical materials that a civil architect uses than we do about a software developer's raw material. Hence the need to study existing software systems more deeply.

    Civil architecture has made tremendous progress over the years in its understanding of materials, but the scale of its creations has not grown commensurately other what the ancients built. But the discipline has a legacy of studying the works of the masters.

    Finally he listed a number of books that document patterns in physical and civil systems, including The Elements of Style -- not the Strunk and White version -- and the books of Christopher Alexander, the godfather of the software patterns movement.

    Booch's goal is for the software community to document software architectures in as great detail, both for history's sake and for the patterns that will help us create more and more beautiful systems. His project is one man's beginning, and an inspirational one at that. In addition to documenting classic systems such as MacPaint, he aims to preserve our classic software as well. That will enable us to study and appreciate it in new ways as our understanding of computing and software grow.

    He closed his talk with inspiration but also a note of warning... He told the story of contacting Edsger Dijkstra to tell him about the handbook project and seek his aid in the form of code and papers and other materials from Dijkstra's personal collection. Dijkstra supported the project enthusiastically and pledged materials from his personal library -- only to die before the details had been formalized. Now, Booch must work through the Dijkstra estate in hopes of collecting any of the material pledged.

    We are a young discipline, relatively speaking, but time is not on our side.


    Posted by Eugene Wallingford | Permalink | Categories: Computing, Patterns, Software Development

    October 25, 2005 8:43 PM

    OOPSLA This and That 3: Geek Jargon

    Get a bunch of technology folks together for any time and they are bound to coin some interesting words, or use ones they've coined previously, either out of habit or to impress their friends. The Extravagaria gang was no exception.

    Example 1: When someone asked how many of us were left-handed, Dick Gabriel said that he was partially ambidextrous, to which Guy Steele volunteered that he was ambimoustrous. I like.

    Example 2: At lunch, Guy Steele asked us if we ever intentionally got lost in a town, perhaps a town new to us, so that we had to learn the place in order to get back to a place we knew. Several people nodded vigorous agreement, and John Dougan noted that he and his colleagues use a similar technique to learn a new legacy code base. They call this air-drop programming. This is a colorful analogy for a common pattern among software developers. Sometimes the best way to learn a new framework or programming language is to parachute behind enemy lines, surrender connection to any safety nets outside, and fight our way out. Or better, not fight, but methodically conquer the new terrain.

    But the biggest source of neologisms at the workshop was our speaking stick. At a previous Extravagaria workshop, Dick used a moose as the communal speaking stick, in honor of Vancouver as the host city. (Of course, there are probably as many moose in San Diego as in Vancouver, but you know, the Great White North and all.) He had planned to bring the moose to this workshop but left it at home accidentally. So he went to a gift shop and bought a San Diego-themed palm tree to use in its place. The veterans of the workshop dubbed it "the moose" out of one year's worth of tradition, and from there we milked the moose terminology with abandon.

    Some of my favorites from the day:

    • on the moose -- back in session; on the clock
    • moose cycles -- a measure of the speed of communication around the group, signified in the passing of the moose
    • virtual moose -- speaking without the moose, but with implicit group permission (We didn't always follow our own rules!)
    • "Moose! Moose!" -- "Me next!"

    Even computer professionals, even distinguished computing academics, surrender to the silliness of a good game. Perhaps we take joy in binding objects to names and growing systems of names more than most.

    I suppose that I should be careful reporting this, because my students will surely hold it over my head at just the right -- or wrong -- moment!


    Posted by Eugene Wallingford | Permalink | Categories: General, Software Development

    October 24, 2005 7:36 PM

    OOPSLA Day 3: Sussman on Expressing Poorly-Understood Ideas in Programs

    Gerald Sussman is renown as one of the great teachers of computing. He co-authored the seminal text Structure and Interpretation of Computer Programs, which many folks -- me included -- think is the best book ever written about computer science. Along with Guy Steele, he wrote an amazing series of papers, collectively called the "Lambda papers", that taught me as much as any other source about programming and machines. It also documented the process that created Scheme, one of my favorite languages.

    Richard Gabriel introduced on Sussman before his talk with an unambiguous statement of his own respect for the presenter, saying that when Sussman speaks, "... record it at 78 and play it back at 33." In inimitable Gabriel fashion, he summarized his career as, "He makes things. He thinks things up. He teaches things."

    Sussman opened by asserting that programming is, at its foundation, a linguistic phenomenon. It is a way in which we express ourselves. As a result, computer programs can be both prose and poetry.

    In programs, we can express different kinds of "information":

    • knowledge of world as we know it
    • models of possible worlds
    • structures of beauty
    • emotional content

    The practical value that we express in programs sometimes leads to the construction of intellectual ideas, which ultimately makes us all smarter.

    Sussman didn't say anything particular about why we should seek to express beauty and emotional content in programs, but I can offer a couple of suggestions. We are more likely to work harder and deeper when we work on ideas that compel us emotionally. This is an essential piece of advice for graduate students in search of thesis topics, and even undergrads beginning research. More importantly, I think that great truths possess a deep beauty. When we work on ideas that we think are beautiful, we are working on ideas that may ultimately pay off with deeper intellectual content.

    Sussman then showed a series of small programs, working his way up the continuum from the prosaic to the beautiful. His first example was a program he called "useful only", written in the "ugliest language I have ever used, C". He claimed that C is ugly because it is not expressive enough (there are ideas we want to express that we cannot express easily or cleanly) and because "any error that can be made can be made in C".

    His next example was in a "slightly nicer language", Fortran. Why is Fortran less prosaic than C? It doesn't pretend to be anything more than it is. (Sussman's repeated use of C as inelegant and inexpressive got a rise out of at least one audience member, who pointed out afterwards that many intelligent folks like C and find it both expressive and elegant. Sussman agreed that many intelligent folks do, and acknowledged that there is room for taste in such matters. But I suspect that he believes that folks who believe such things are misguided or in need of enlightenment. :-)

    Finally Sussman showed a program in a language we all knew was coming, Scheme. This Scheme program was beautiful because it allows us to express the truth of the domain, that states and differential states are computed by functions that can be abstracted away, that states are added and subtracted just like numbers. So, the operators + and must be generic across whatever value set we wish to compute over at the time.

    In Scheme, there is nothing special about + or . We can define them to mean what they mean in the domain where we work. Some people don't like this, because they fear that in redefining fundamental operations we will make errors. And they are right! But addition can be a fundamental operation in many domains with many different meanings; why limit ourselves? Remember what John Gribble and Robert Hass told us: you have to take risks to create something beautiful.

    This point expresses what seemed to be a fulcrum point in Sussman's argument: Mathematics is a language, not a set of tools. It is useful to us to the extent we we can express the ideas that matter to us.

    Then Sussman showed what many folks consider to be among the most beautiful pieces of code ever written, if not the most beautiful: Lisp's eval procedure written in Lisp. This may be as close to Maxwell's equations in computer science as possible.

    This is where Sussman got to the key insight of his talk, the insight that has underlay much of his intellectual contribution to our world:

    There are some things we could not express until we invented programming.

    Here Sussman distinguished two kinds of knowledge about the world, declarative knowledge and imperative knowledge. Imperative knowledge is difficult to express clearly in an ambiguous language, which all natural languages are. A programming language lets us express such knowledge in a fundamentally new way. In particular, computer programs improve our ability to teach students about procedural knowledge. Most every computer science student has had the experience of getting some tough idea only after successfully programming it.

    Sussman went further to state baldly, "Research that doesn't connect with students is a waste." To the extent that we seek new knowledge to improve the world around us, we must teach it to others, so I suppose that Sussman is correct.

    Then Sussman clarified his key insight, distinguishing computer programs from traditional mathematics. "Programming forces one to be precise and formal, without being excessively rigorous." I was glad that he then said more specifically what he means here by 'formal' and 'rigorous'. Formality refers to lack of ambiguity, while rigor referd to what a particular expression entails. When we write a program, we must be unambiguous, but we do not yet have to understand the full implication of what we have written.

    When we teach students a programming language, we are able to have a conversation with them of the sort we couldn't have before -- about any topic in which procedural knowledge plays a central role. Instead of trying to teach students to abstract general principles from the behavior of the teacher, a form of induction, we can now give them a discursive text that expresses the knowledge directly.

    In order to participate in such a conversation, we need only know a few computational ideas. One is the lambda calculus. All that matters is that you have a uniform system for naming things. "As anyone who has studied spirituality knows, if you give a name to a spirit, you have power over it." So perhaps the most powerful tool we can offer in computing is the ability to construct languages quickly. (Use that to evaluate your favorite programming language...)

    Sussman liked the Hass lecture, too. "Mr. Hass thinks very clearly. One thing I've learned is that all people, if they are good at what they do, whatever their area -- they all think alike." I suspect that this accounts for why many of the OOPSLA crowd enjoyed the Hass lecture, even if they do not think of themselves as literary or poetic; Hass was speaking truths about creativity and beauty that computer scientists know and live.

    Sussman quoted two artists whose comments echoed his own sentiment. First, Edgar Allan Poe from his 1846 The Philosophy of Composition:

    ... it will not be regarded as a breach of decorum on my part to show the modus operandi by which some one of my own works was put together. I select "The Raven" as most generally known. It is my design to render it manifest that no one point in its composition is referable either to accident or intuition -- that the work proceeded step by step, to its completion with the precision and rigid consequence of a mathematical problem.

    And then concert pianist James Boyk:

    A work of art is a machine with an aesthetic purpose.

    (I am uncomfortable with the impression these quotes give, that artistic expression is mechanistic, though I believe that artistic work depends deeply on craft skills and unromantic practice.)

    Sussman considers himself an engineer, not a scientist. Science believes in a "talent theory" of knowledge, in part because the sciences grew out of the upper classes, which passed on a hereditary view of the world. On the other hand, engineering favors a "skill theory" of knowledge; knowledge and skill can be taught. Engineering derived from craftsmen, who had to teach their apprentices in order to construct major artifacts like cathedrals; if the product won't be done in your lifetime, you need to pass on the skills needed for others to complete the job!

    The talk went on for a while thereafter, with Sussman giving more examples of using programs as linguistic expressions in electricity and mechanics and mathematics, showing how a programming language enables us -- forces us -- to express a truth more formally and more precisely than what our old mathematical and natural languages did.

    Just as most programmers have experienced the a-ha! moment of understanding after having written a program in an area we were struggling to learning, nearly every teacher has had an experience with a student who has unwittingly bumped into the wall at which computer programming forces us to express an idea more precisely than our muddled brain allows. Just today, one of my harder-working students wrote me in an e-mail message, "I'm pretty sure I understand what I want to do, but I can't quite translate it into a program." I empathize with his struggles, but the answer is: You probably don't understand, or you would be able to write the program. In this case, examination of the student's code revealed the lack of understanding that manifests itself in a program far more complex than the idea itself.

    This was a good talk, one which went a long way toward helping folks see just how important computer programming is as an intellectual discipline, not just as a technology. I think that one of the people who made a comment after the talk said it well. Though the title of this talk was "Why Programming is a Good Medium for Expressing Poorly Understood and Sloppily Formulated Ideas", the point of this talk is that, in expressing poorly-understood and sloppily-formulated ideas in a computer program, we come to understand them better. In expressing them, we must eliminate our sloppiness and really understand what we are doing. The heart of computing lies in the computer program, and it embodies a new form of epistemology.


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

    October 20, 2005 6:46 PM

    OOPSLA This and That, Part 2

    As always, OOPSLA has been a constant font of ideas. But this year's OOPSLA seems to have triggered even more than its usual share. I think that is a direct result of the leadership of Dick Gabriel and Ralph Johnson, who have been working for eighteen months to create a coherent and focused program. As much as I have already written this week -- and I know that some of my articles have been quite long; sorry for getting carried away... -- I have plenty of raw material to keep me busy for a while, including the rest of the Educators Symposium, Gerald Sussman's invited talk, my favorite neologism of the week, and the event starting as I type this: Grady Booch's conference-closing talk on his ambitious project to build a handbook of software architecture.

    For now, I'd like to share just a few ideas from the two panels I attended in the middle part of this fine last day of OOPSLA.

    The Echoes panel was aimed at exploring the echoes of the structured design movement of the late 1970s. It wasn't as entertaining or as earth-shaking as it might have been given its line-up of panelists, but I took away two key points:

    • Kent Beck said that he recently re-read Structured Design and was amazed how much of the stuff we talk about today is explained in that book. I remember reading that book for the first time back in 1985, after reading Structured Analysis and System Specification in my software engineering senior sequence. They shaped how I thought about software construction.

      I plan to re-read both books in the next year.

    • Grady Booch said that no one reads code, not like folks in other disciplines read the literature of their disciplines. And code is in many ways the real literature that we are creating. I agree with Grady and have long thought about how the CS courses we teach could encourage students to read real programs -- say, in operating systems, where students can read Linux line by line if they want. Certainly, I do this my compilers course, but not with a non-trivial program. (Well, my programming languages students usually read a non-trivial interpreter, a Scheme interpreter written in Scheme modeled on McCarthy's original Lisp interpreter. That program is small but not trivial. It is the Maxwell equations of computing.)

      I am going to think about how to work this idea more concretely into the courses I teach in the next year.

    Like Echoes, the Yoshimi Battles the Pink Robots panel -- on the culture war between programmers and users -- didn't knock my socks off, but Brian Foote was in classic form. I don't think that he was cast in the role of Yoshimi, but he defended the role of the programmer qua programmer.

    • His position statement quoted Howard Roark, the architect in Ayn Rand's The Fountainhead: "I don't build in order to have clients. I have clients in order to build."

      I immediately thought of a couple of plays on the theme of this quote:

      I don't teach to have students. I have students to teach.
      I don't blog to have readers. I have readers to blog.

    • Brian played on words, too, but not Howard Roark's. He read, in his best upper-crust British voice, the lyrics of "I Write the Code", with no apologies at all to Barry Manilow.
      I am hacker, and I write the code.

    • And this one was Just Plain Brian:
      You know the thing that is most annoying about users is that they have no appreciation for the glory, the grandeur, or the majesty of living inside the code. It is my cathedral.

    Oh: on his way into the lecture to give his big talk, Grady Booch walked by, glanced at my iBook, and said, "Hey, another Apple guy. Cool."

    It's been a good day.


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

    October 20, 2005 3:57 PM

    OOPSLA Day 5: Martin Fowler on Finding Good Design

    Sadly... The last day of OOPSLA is here. It will be a good day, including Onward! Films (or Echoes -- could I possibly skip a panel with Kent and so many Big Names?) (later note: I didn't), Lightning Talks (or the Programmers versus Users panel) (later note: I am at this panel now), and finally, of course, Grady Booch. But then it's over. And I'll be sad.

    On to Martin or, as he would say, Mah-tin. Ralph Johnson quoted Brian Foote's epigrammatic characterization of Martin: an intellectual jackal with good taste in carrion. Soon, Ralph began to read his official introduction of Martin, written by ... Brian. It was a play on the location of conference, in Fashion Valley. In the fashion world, good design is essential, and we know our favorite designers by one name: Versace, Halston, Kent, Ward -- and Mah-tin. Martin lives a life full of beautiful models, and he is "a pretty good writer, for an Englishman".

    On came Martin. He roamed the full stage, and then sat down in a cushy chair.

    When asked to keynote at a conference like OOPSLA, one is flush with pride. Then you say 'yes', which is your first mistake. What can you say? Keynoters are folks who make great ideas, who invent important stuff. Guy's talks was the best. But I'm not a creator or deep thinker, says... I'm that guy who goes to a fashion show, steals the ideas he sees, knocks off the clothing, and then mass-markets them at the mall. I just want to know where we are, says Martin; predicting the future is beyond me.

    To shake things up, he called on George Platts to the stage. Those of you who have attended a PLoP conference know George as a "lateral thinking consultant" and games leader. Earlier, Martin had asked him to create a game for the whole crowd, designed to turn us into intellectual jackals. For this game, George drew his inspiration from the magnificent book Life of Pi. (Eugene says: If you have not read this book, do it. Now.) George read a list of animal sounds from one page in the book and told each of us to choose one. He then told each of us to warm up by saying our own name in that fashion. (I grunted "Eugene"). He then asked everyone whose first name started with A to stand and do it for the crowd. Then I and R; D, M, V; G, P, Y; ... and finally E, N, and W. Finally, the whole room stood and hissed, grunted, growled "OOPSLA".

    Back came Martin to the forefront, for the talk itself.

    Martin's career is aimed at answering the question, "What is good design?" He seeks an answer that is more than just fuzzy words and fuzzy ideas.

    At the beginning of his career, Martin was an EE. In that discipline, designers drawing a diagram that delineate a product and then passes it on to the person who constructs the thing. So when Martin moved on to software engineering, which had adopted this approach. But soon he came to reject this approach. Coding as construction fails. He found that designs -- other people's design and his own -- always turned out to be wrong. Eventually, he met folks he recognized as good designers who design and code at the same time. Martin came to see that the only way to design well is to program at the same time, and the only way to program well is to design at the same time.

    That's the philosophy underlying all of Martin's work.

    How do we characterize good designs? A set of principles.

    One principle central to all good designs is to eliminate duplication. He remembers when Kent told him this, but at the time Martin dismissed it as not very deep. But then he saw that there is much more to this than he first\ thought. It turns out that when you eliminate duplication, your designs end up good, almost irrespective of anything else. He noted that this has been pattern in his life: see an important idea, dismiss it, and eventually come around. (And then write a book about it. :-)

    Another principle: orthogonality, the notion that different parts of a system should do different kinds of things.

    Another principle: separate the user interface from the guts of the program. One way to approach this is to imagine you have to add a new UI to your system. Any code you would have to duplicate is in the wrong place.

    Philosophy. Principles. What is the next P?

    Patterns -- the finding of recurring structures. Martin turned to Ralph Johnson, who has likened pattern authors to Victorian biologists, who went off to investigate a single something in great detail -- cataloging and identifying and dissecting and classifying. You learn a lot about the one thing, but you also learn something bigger. Consider Darwin, who ultimately created the theory of natural selection.

    The patterns community is about finding that core something which keeps popping in a slightly different way all over the place. Martin does this in his work. He then did a cool little human demonstration of one of the patterns from his Patterns of Enterprise Application Architecture, an event queue. In identifying and naming the pattern, he found so many nice results, including some unexpected ones, like the ability to rewind and reply transactions.

    Patterns people "surface" core ideas, chunk them up into the right scale, and identify when and when not to use them.

    Why isn't the patterns community bigger? Martin thinks it should be bigger, and in particular should be a standard part of every academic's life! We academics should go out, look at big old systems for a couple of months, and try to make sense of them.

    At the end of the session, James Noble pointed out two reasons why academic programmers don't do this: they do not receive academic credit for such activity, and they do not have access to the large commercial systems that they really need to study. On the first point, Martin agreed. This requires a shift in the academic culture, which is hard to do. (This issue of academic culture, publishing, and so on came up again at the Echoes panel later in the morning.) Martin volunteered to bellow in that direction whenever and wherever asked. On the second point, he answered with an emphatic 'yes!' Open source software opens a new avenue for this sort of work...

    Philosophy. Principles. Patterns. What is the last P?

    Practices. His favorite is, of course, refactoring. He remembers watching Kent Beck editing a piece of code of Martin Fowler code. Kent kept making these small, trivial changes to the code, but after each step Martin found himself saying, "Hmm, that is better." The lightbulb went off again.

    He thanked John Brant and Don Roberts, Bill Opdyke and Ralph Johnson, and Ward and Kent. It's easy to write good books when other people have done the deep thinking.

    He then pointed to Mary Beth Rosson's project that asks students to fixing code as a way to learn. (Eugene thinks: But that's not refactoring, right?) Refactoring is a good practice for students as they learn. "Here is some code. Smell it. Come back when it's better."

    My students had better get ready...

    Another practice that Martin lives and loves is test-driven design. Of course,it embodies the philosophy he began this talk with: You design and program at the same time.

    And thus endeth the lesson.

    In addition to the comment on academics and patterns, James Noble asked another question. (Martin lamented, "First I was Footed, and now I am Nobled." If you know Foote and Noble, you can imagine why this prospect would have a speaker a bit on edge.) James played it straight, except for a bit of camera play with the mic and stage, and pointed out that separating the UI ought causes an increase in the total amount of code -- he claimed 50%. How is that better? Martin: I don't know. Folks have certainly questioned this principle. But then, we often increase duplication in order to make it go away; maybe there is a similarity here?

    Or, as Martin closed, maybe he is just wrong. If so, he'll learn that soon enough.


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

    October 19, 2005 8:17 PM

    More on Safety and Freedom in the Extreme

    giving up liberty for safety

    In my entry on Robert Hass's keynote address, I discussed the juxtaposition of 'conservative' and 'creative', the tension between the desire to be safe and the desire to be free, between memory and change. Hass warned us against the danger inherent in seeking safety, in preserving memory, to an extreme: blindness to current reality. But he never addressed the danger inherent in seeking freedom and change to the exclusion of all else. I wrote:

    There is a danger in safety, as it can blind us to the value of change, can make us fear change. This was one of the moments in which Hass surrendered to a cheap political point, but I began to think about the dangers inherent in the other side of the equation, freedom. What sort of blindness does freedom lead us to?

    giving up safety for liberty

    During a conversation about the talk with Ryan Dixon, it hit me. The danger inherent in seeking freedom and change to an extreme untethered idealism. Instead of "Ah, the good old days!", we have, "The world would be great if only...". When we don't show proper respect to memory and safety, we become blind in a different way -- to the fact that the world can't be the way it is in our dreams, that reality precludes somehow our vision.

    That doesn't sound so bad, but people sometimes forget not to include other people in their ideal view. We sometimes become so convinced by our own idealism that we feel a need to project it onto others, regardless of their own desires. This sort of blindness begins to look in practice an awful lot like the blindness of overemphasizing safety and memory.

    Of course, when discussing creative habits, we need to be careful not to censor ourselves prematurely. As we discussed at Extravagaria, most people tend toward one extreme. They need encouragement to overcome their fears of failure and inadequacy. But that doesn't mean that we can divorce ourselves from reality, from human nature, from the limits of the world. Creativity, as Hass himself told us, thrives when it bumps into boundaries.

    Being creative means balancing our desire for safety and freedom. Straying too far in either way may work in the short term, but after too long in either land we lose something essential to the creative process.


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

    October 19, 2005 6:14 PM

    OOPSLA Day 4: Mary Beth Rosson on the End of Users

    As you've read here in the past, I am one of a growing number of CS folks who believe that we must expand the purview of computer science education far beyond the education of computer scientists and software developers. Indeed, our most important task may well lie in the education of the rest of the educated world -- the biologists and sociologists, the economists and physicists, the artists and chemists and political scientists whose mode of work has been fundamentally altered by the aggregation of huge stores of data and the creation of tools for exploring data and building models. The future of greatest interest belongs not to software development shops but to the folks doing real work in real domains.

    Mary Beth Rosson

    So you won't be surprised to know how excited I was to come to Mary Beth Rosson's Onward! keynote address called "The End of Users". Mary Beth has been an influential researcher across a broad spectrum of problems in OOP, HCI, software design, and end-user programming, all of which have had prominent places at OOPSLA over the years. The common theme to her work is how people relate to technology, and her methodology has always had a strong empirical flavor -- watching "users" of various stripes and learning from their practice how to better support them.

    In today's talk, Mary Beth argued that the relationship between software developers and software users is changing. In the old days, we talked about "end-user programming", those programming-like activities done by those without formal training in programming. In this paradigm, end users identify requirements on programs and then developers produce software to meet the need. This cycle occurs at a relatively large granularity, over a relatively long time line.

    But the world is changing. We now find users operating in increasingly complex contexts. In the course of doing their work, they frequently run into ad hoc problems for their software to solve. They want to integrate pieces of solution across multiple tools, customize their applications for specific scenarios, and appropriate data and techniques from other tools. In this new world, developers must produce components that can be used in an ad hoc fashion, integrated across apps. Software developers must create knowledge bases and construction kits that support an interconnected body of problems. (Maybe the developers even strive to respond on demand...)

    These are not users in the traditional sense. We might call them "power users", but that phrase is already shop-worn. Mary Beth is trying out a new label: use developers. She isn't sure whether this label is the long-term solution, but at least this name recognizes that users are playing an increasingly sophisticated role that looks more and more like programming.

    What sorts of non-trivial tasks do use developers do?

    An example scenario: a Word user redefining the 'normal' document style. This is a powerful tool with big potential costs if done wrong.

    Another scenario: an Excel user creates a large spreadsheet that embodies -- hides! -- a massive amount of computation. (Mary Beth's specific example was a grades spreadsheet. She is a CS professor after all!)

    Yet another: an SPSS defines new variables and toggles between textual programming and graphical programming.

    And yet another: a FrontPage user does visual programming of a web page, with full access to an Access database -- and designs a database!

    Mary Beth summarized the characteristics of use developers as:

    • comfortable with a diverse array of software apps and data sources
    • work with them multiple apps in parallel and so want to pick and choose among functionality at any time, hooking components up and configuring custom solutions on demand.
    • working collaboratively, with group behaviors emerging
    • see the computer as a tool, not an end; it should not get in their way

    Creating use developers has potential economic benefits (more and quicker cycles getting work done) and personal benefits (more power, more versatility, higher degree of satisfaction).

    But is the idea of a use developer good?

    Mary Beth quoted an IEEE Software editor whose was quite dismissive of end users. He warned that they do not systematically test their work, that they don't know to think about data security and maintainability, and -- when they do know to think about these issues -- they don't know *how* to think about them. Mary Beth thinks these concerns are representative of what folks in the software world and that we need to be attentive to them.

    (Personally, I think that, while we certainly should be concerned about the quality of the software produced by end users, we also must keep in mind that software engineers have a vested interested in protecting the notion that only Software Engineers, properly trained and using Methods Anointed From On High are capable of delivering software of value. We all know of complaints from the traditional software engineering community about agile software development methods, even when the folks implementing and using agile methods are trained in computing and are, presumably, qualified to make important decisions about the environment in which we make software.)

    Mary Beth gave an example to illustrate the potential cost inherent in the lack of dependability -- a Fannie Mae spreadsheet that contained a $1.2B error.

    As the base of potential use developers grows so do the potential problems. Consider just the spreadsheet and database markets... By 2012, the US Department of Labor estimates that there will be 55M end users. 90% of all spreadsheets contain errors. (Yes, but is that worse or better than in programs written by professional software developments?) The potential costs are not just monetary; they can be related to the quality of life we all experience. Such problems can be annoying and ubiquitous: web input forms with browser incompatibilities; overactive spam filters that lose our mail; Word styles that break the other formatting in user documents; and policy decisions based on research findings that themselves are based on faulty analysis due to errors in spreadsheets and small databases.

    Who is responsible for addressing these issues? Both! Certainly, end users must take on the responsibility of developing new habits and learning the skills they need to use their tools effectively and safely. But we in the software world need to recognize our responsibilities:

    • to build better tools, to build the scaffolding users need to be effective and safe users. The tools we build should offer the right amount of help to users who are in the moment of doing their jobs.
    • to promote a "quality assurance" culture among users. We need to develop and implement new standards for computing literacy courses.

    How do we build better tools?

    Mary Beth called them smarter tools and pointed to a couple of the challenges we must address. First, much of the computation being done in tools is invisible, that is, hidden by the user interface. Second, people do not want to be interrupted while doing their work! (We programmers don't want that; why should our users have to put up with it?)

    Two approaches that offer promise are interactive visualization of data and minimalism. By minimalism, she means not expanding the set of issues that the user has concern herself with by, say, integrating testing and debugging into the standard usage model.

    The NSF is supporting a five-school consortium called EUSES, End Users Shaping Effective Software, who are trying these ideas out in tool and experiment. Some examples of their work:

    • CLICKS is a drag-and-drop, design-oriented web development environment.

    • Whyline is a help system integrated directly into Alice's user environment. The help system monitors the state of the user's program and maintains a dynamic menu of problems they may run into.

    • WYSIWYT is a JUnit-style interface for debugging spreadsheets, in which the system keeps an eye on what cells have and have not been verified with tests.

    How can we promote a culture of quality assurance? What is the cost-benefit trade-off involved for the users? For society?

    Mary Beth indicated three broad themes we can build on:

    • K-12 education: making quality a part of schoolchildren's culture of computer use
    • universal access: creating tools aimed at specific populations of users
    • communities of practice: evolving reflective practices within the social networks of users

    Some specific examples:

    • Youngsters who learn by debugging in Alice. This is ongoing work by Mary Beth's group. Children play in 3D worlds that are broken, and as they play the child users are invited to fix the system as they play. You may recognize this as the Fixer Upper pedagogical pattern, but in a "non-programming" programming context.

    • Debugging tools that appeal to women. Research shows that women take debugging seriously, but they tend to use strategies in their heads more than the tools available in the typical spreadsheet and word processing systems. How do we invite women with lower self-confidence to avail themselves of system tools? One experimental tool does this by letting users indicate "not sure" when evaluating correctness of a spreadsheet cell formula.

    • Pair programming community simulations. One group has has a Sim City-like world in which a senior citizen "pair programs" with a child. Leaving the users unconstrained led to degeneration, but casting the elders as object designers and the children as builders led to coherent creations.

    • Sharing and reuse in a teacher community. The Teacher Bridge project has created a collaborative software construction tool to support an existing teacher community. The tool has been used by several groups, including the one that created PandapasPond.org. This tool combines a wiki model for its dynamic "web editor" and more traditional model for its static design tool (the "folder editor"). Underneath the service, the system can track user activity in a variety of ways, which allows us to explore the social connections that develop within the user community over time.

    The talk closed with a reminder that we are just beginning the transition from thinking of "end users" to thinking of "use developers", and one of our explicit goals should be to try to maximize the upside, and minimize the downside, of the world that will result.

    For the first time in a long time, I got up to ask a question after one of the big talks. Getting up to stand in line at an aisle mic in a large lecture hall, to ask a question in front of several hundred folks, seems a rather presumptuous act. But my interest in this issue is growing rapidly, and Mary Beth has struck on several issues close to my current thinking.

    My question was this: What should university educators be thinking about with regard to this transition? Mary Beth's answer went in a way I didn't anticipate: We should be thinking about how to help users develop the metacognitive skills that software developers learn within our culture of practice. We should extend cultural literacy curricula to focus on the sort of reflective habits and skills that users need to have when building models. "Do I know what's going on? What could be going wrong? What kinds of errors should I be watching for? How can I squeeze errors out of my program?"

    After the talk, I spent a few minutes discussing curricula issues more specifically. I told her about our interest in reaching out to new populations of students, with the particular example of a testing certificate that folks in my department are beginning to work on. This certificate will target non-CS students, the idea being that many non-CS students end up working as testers in software development for their domain, yet they don't understand software or testing or much anything about computing very deeply. This certificate is still aimed at traditional software development houses, though I think it will bear the seeds of teaching non-programmers to think about testing and software quality. If these folks ever end up making a spreadsheet or customizing Word, the skills they learn here will transfer directly.

    Ultimately, I see some CS departments expanding their computer literacy courses, and general education courses, to aim at use developers. Our courses should treat them with the same care and respect as we treat Programmers and Computer Scientists. The tasks users do are important, and these folks deserve tools of comparable quality.

    Three major talks, three home runs. OOPSLA 2005 is hot.


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

    October 19, 2005 10:11 AM

    OOPSLA Day 1: Writing Exercises at Extravagaria

    I am nobody:
    A red sinking autumn sun
    Took my name away.

    -- Richard Wright

    As I noted before, I nearly blew off Sunday, after a long and tiring two days before. As you might have gathered from that same entry, I am happy that I did not. The reasons should be obvious enough: cool ideas happen for me only when I am engaged with ideas, and the people and interactions at Extravagaria were a source of inspiration that has remained alive with me throughout the rest of the conference.

    In the afternoon of the workshop, we did two group exercises to explore issues in creativity -- one in the realm of writing poetry, and one in the realm of software design.

    Gang-Writing Haiku

    Haiku is a simple poetic form that most of us learn as schoolchildren. It is generally more involved than we learn in school, with specific expectations on the content of the poems, but at its simplest it is a form of three lines, consisting of 5, 7, and 5 syllables, respectively.

    If I understood correctly, a tonka is a poem constructed by following a haiku with a couplet in which line is 7 syllables. We can go a step further yet, by connecting a sequence of tonkas into a renga. John called the renga the "stretch limo" of haiku. Apparently, the Japanese have a traditional drinking game that requires each person to write a verse of a growing renga in turn, taking a drink with each verse. The poems may degenerate, but the evening is probably not a complete loss...

    Our first exercise after lunch was a variation of this drinking game, only without the drinking. We replaced the adult beverages with two features intended to encourage and test our creativity. First, we were given one minute or less to write each verse. Second, when we passed the growing poem on to the next writer, we folded it over so that the person could see only the verse we had just written.

    Rather than start with scratch, John seeded our efforts with haiku written by the accomplished American novelist Richard Wright. In the last eighteen months of his life, Wright became obsessed with haiku, writing dozens a day. Many of these works were published in a collection after his death. John gave each of person a haiku from this collection. One of them, my favorite, appears at the top of this essay.

    Then we were off, gang-writing poetry. My group consisted of Brian Foote, Joe Yoder, Danny Dig, Guy Steele, and me. Each of us started with a Wright haiku, wrote a couplet in response to it, folded Wright's stanza under, and passed the extended poem on to continue the cycle. After a few minutes, we had five renga. (And yet we were sober, though the quality of the poetry may not have reflected that. :-)

    The second step of the exercise was to select our favorite, the one we thought had the highest quality. My group opted for a two-pass process. Each of us cast a vote for our two favorites, and the group then deliberated over the the top two vote-getters. We then had the opportunity to revise our selection before sharing it with the larger group. (We didn't.) Then each of the groups read its best product to the whole group.

    My group selected the near-renga we called Syzygy Matters (link to follow) as our best. This was not one of my two favorites, but it was certainly in line with my choices. One poem I voted for received only my vote, but I won't concede that it wasn't one of our best. I call it Seasons Cease.

    Afterwards, we discussed the process and the role creativity played.

    • Most of us tried to build on the preceding stanza, rather than undo it.

    • This exercise resembles a common technique in improvisational theater. There, the group goes through rounds of one sentence per person, building on the preceding sentences. Sometimes, the participants cycle through these conjunctions in order: "Yes, and...", "No, and...", "Yes, but...", and "No, but...".

    • Time pressure matters.

    • Personally, I noticed that by moving so fast that I had no chance to clear my mind completely, a theme developed in my mind that carried over from renga to renga. So my stanzas were shaped both by the stanza I was handed and by the stanza I wrote in the previous round.

    • Guy was optimistic about the process but pessimistic about the products. The experience lowered his expectations for the prospects for groups writing software by global emergence from local rules.

    • We all had a reluctance to revise our selected poems. The group censored itself, perhaps out of fear of offending whoever had written the lines. (So much for Common Code Ownership.) Someone suggested that we might try some similar ideas for the revision process. Pass all the poems we generated to another group, which would choose the best of the litter. Then we pass the poem on to a third group, which is charged with revising the poem to make it better. This would eliminate the group censorship effect mentioned above, and it would also eliminate the possibility that our selection process was biased by personal triggers and fondness.

    • Someone joked that we should cut the first stanza, the one written by Wright!, because it didn't fit the style of the rest of the stanzas. Joke aside, this is often a good idea. Often, we need to let go of the triggers that initially caused us to write. That can be true in our code, as well. Sometimes a class that appears early in a program ultimately outlives its utility, its responsibilities distributed across other more vital objects. We shouldn't be afraid of cutting the class,but sometimes we hold an inordinate attachment to the idea of the class.

    • To some, this exercise felt more like a white-board design session than a coding exercise. We placed a high threshold on revisions, as we often do for group brainstorm designs.

    • Someone else compared this to design by committee, and to the strategy of separating the coding team from the QA team.

    Later, we discussed how, in technical writing and other non-fiction, our goal is to make the words we use match the truth as much as possible, but sometimes an exaggeration can convey truth even better. Is such an exaggeration "more true" than the reality, by conveying better the feel of a situation than pure facts would have? Dick used the re-entry season from Apollo 13 as an example.

    (Aside: This led to a side discussion of how watching a movie without listening to its soundtrack is usually avery different experience. Indeed, most directors these days use the music as an essential story-telling device. What if life were like that? Dick offered that perhaps we are embarking on a new era in which the personal MP3 player does just that, adding a soundtrack to our lives for our own personal consumption.)

    A good story tells the truth better than the truth itself. This is true in mathematical proofs, where the proof tells a story quite different from the actual process by which a new finding is reached. It is true of papers on software system designs, of software patterns. this is yet another way in which software and computer science are like poetry and Mark Twain.

    A Team Experiment with Software Design

    The second exercise of the afternoon asked four "teams" -- three of size four, and the fourth being Guy Steele alone -- to design a program that could generate interesting Sudoku puzzles. Half way through our hour, two teams cross-pollinated in a Gabriel-driven episode of crossover.

    I don't have quite as much to save about this exercise. It was fun thinking about Sudoku, a puzzle I've started playing a bit in the last few weeks. It was fun watching working with Sudoku naifs wrap their games around the possibilities of the game. It was especially fun to watch a truly keen mind describe how he attacked and solved a tough problem. (I saved Guy's handwritten draft of his algorithm. I may try to implement it later. I feel like a rock star groupie...)

    The debrief of this exercise focused on whether this process felt creative in the sense that writing haiku did, or was it more like the algorithm design exercise one might solve on a grad school exam, taken from Knuth. Guy pointed out that these are not disjoint propositions.

    What feels creative is solving something we don't yet understand -- creativity lies in exploring what do not understand, yet. For example, writing a Sudoku solver would have involved little or no creativity for most of us, because it would be so similar to backtracking programs we have written before, say, to solve the 8-queens puzzle.

    In many ways, these exercises aren't representative of literary creativity, in several significant ways. Most writers work solo, rather than in groups. Creators may work under pressure, but not often in 1-minute compressions. But sprints of this sort can help jolt creativity, and they can expose us to models of work,models we can adopt and adapt.

    One thing seems certain: Change begets creativity. Robert Hass spoke of the constant and the variable, and how -- while both are essential to creativity -- it is change and difficulty that are usually the proximate causes of the creative act. That's why cross-pollination of teams (e.g., pair programmers) works, and why we should switch tools and environments every so often, to jog the mind to open itself to creating something new.


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

    October 18, 2005 4:04 PM

    OOPSLA Day 3: Robert Hass on Creativity

    Robert Hass, former poet laureate of the US

    With Dick Gabriel and Ralph Johnson leading OOPSLA this year, none of us were that the themes of the conference were creativity and discovery. This theme presented itself immediately in the conference's opening keynote speaker, former poet laureate Robert Hass. He gave a marvelous talk on creativity.

    Hass began his presentation by reading a poem (whose name I missed) from Dick's new chapbook, Drive On. Bob was one of Dick's early teachers, and he clearly reveled in the lyricism, the rhythm of the poem. Teachers often form close bonds with their students, however long or short the teaching relationship. I know the feeling from both sides of the phenomenon.

    He then described his initial panic at thought of introducing the topic of creativity to a thousand people who develop software -- who create, but in a domain so far from his expertise. But a scholar can find ways to understand and transmit ideas of value wherever they live, and Hass is not only a poet but a first-rate scholar.

    Charles Dickens burst on scene with publication of The Pickwick Papers. With this novel, Dickens essentially invented the genre of the magazine-serialized novel. When asked how he created a new genre of literature, he said simply, "I thought of Pickwick."

    I was immediately reminded of something John Gribble said in his talk at Extravagaria on Sunday: Inspiration comes to those already involved in the work.

    Creativity seems to happen almost with cause. Hass consulted with friends who have created interesting results. One solved a math problem thought unsolvable by reading the literature and "seeing" the answer. Another claimed to have resolved the two toughest puzzles in his professional career by going to sleep and waking up with the answer.

    So Hass offered his first suggestion for how to be creative: Go to sleep.

    Human beings were the first animals to trade instinct for learning. The first major product of our learning was our tools. We made tools that reflected what we learned about solving immediate problems we faced in life. These tools embodied the patterns we observed in our universe.

    We then moved on to broader forms of patterns: story, song, and dance. These were,according to Hass, the original forms of information storage and retrieval, the first memory technologies. Eventually, though, we created a new tool, the printing press, that made these fundamentally less essential -- less important!? And now the folks in this room contribute to the ultimate tool, the computer, that in many ways obsoletes human memory technology. As a result, advances in human memory tech have slowed, nearly ceased.

    The bulk of Hass's presentation explored the interplay between the conservative in us (to desire to preserve in memory) and the creative in us (the desire to create anew). This juxtaposition of 'conservative' and 'creative' begets a temptation for cheap political shots, to which even Hass himself surrendered at least twice. But the juxtaposition is essential, and Hass's presentation repeatedly showed the value and human imperative for both.

    Evolutionary creativity depends on the presence having a constant part and a variable part, for example, the mix of same and different in an animal's body, in the environment. The simultaneous presence of constant and variable is the basis of man's physical life. It is also the basis of our psychic life. We all want security and freedom, in an unending cycle Indeed, I believe that most of us want both all the time, at the same time. Conservative and creative, constant and variable -- we want and need both.

    Humans have a fundamental desire for individuation, even while still feeling a oneness with our mothers, our mentors, the sources of our lives. Inspiration, in a way, is how a person comes to be herself -- is in part a process of separation.

    "Once upon a time" is linguistic symbol, the first step of the our separation from the immediate action of reading into a created world.

    At the same time, we want to be safe and close to, free and faraway. Union and individuation. Remembering and changing.

    Most of us think that most everyone else is more creative than we are. This is a form of the fear John Gribble spoke about on Sunday, one of the blocks we must learn to eliminate from our minds -- or at least fool ourselves into ignoring. (I am reminded of John Nash choosing to ignore the people his mind fabricates around him in A Beautiful Mind.)

    Hass then told a story about the siren song from The Odyssey. It turns out that most of the stories in Homer's epics are based in "bear stories" much older than Homer. Anyway, Odysseus's encounter with the sirens is part of a story of innovation and return, freedom on the journey followed by a return to restore safety at home. Odysseus exhibits the creativity of an epic hero: he ties himself to the mast so that he can hear the sirens' song without having to take ship so close to the rocks.

    According to Hass, in some versions of the siren story, the sirens couldn't sing -- the song was only a sailors' legend. But they desire to hear the beautiful song, if it exists. Odysseus took a path that allowed him both safety and freedom, without giving up his desire.

    In preparing for this talk,hass asked himself, "Why should I talk to you about creativity? Why think about it all?" He identified at least four very good reasons, the desire to answer these questions:

    • How can we cultivate creativity in ourselves?
    • How can we cultivate creativity in our children?
    • How can we identify creative people?
    • How can we create environments that foster creativity?

    So he went off to study what we know about creativity. A scholar does research.

    Creativity research in the US began when academic psychologists began trying to measure mental characteristics. Much of this work was done at the request of the military. As time went by, the number of characteristics, perhaps in correlation of research grants awarded by the government. Creativity is, perhaps, correlated with salesmanship. :-) Eventually, we had found several important characteristics, including that there is little or no correlation between IQ and creativity. Creativity is not a province of the intellectually gifted.

    Hass cited the research of Howard Gardner and Mihaly Csikszentmihalyi (remember him?), both of whom worked to identify key features of the moment of a creative change, say, when Dickens thought to publish a novel in serial form. The key seems to be immersion in a domain, a fascination with domain and its problem and possibilities. The creative person learns the language of the domain and sees something new. Creative people are not problems solvers but problem finders.

    I am not surprised to find language at the center of creativity! I am also not surprised to know that creative people find problems. I think we can save something even stronger, that creative people often create their own problems to solve. This is one of the characteristics that biases me away from creativity: I am a solver more than a finder. But thinking explicitly about this may enable me to seek ways to find and create problems.

    That is, as Hass pointed out earlier, one of the reasons for thinking about creativity: ways to make ourselves more creative. But we can use the same ideas to help our children learn the creative habit, and to help create institutions that foster the creative act. He mentioned OOPSLA as a social construct in the domain of software that excels at fostering creative. It's why we all keep coming back. How can we repeat the process?

    Hass spoke more about important features of domains. For instance, it seems matter how clear the rules of the domain are at the point that a person enters it. Darwin is a great example. He embarked on his studies at a time when the rules of his domain had just become fuzzy again. Geology had recently expanded European science's understanding of the timeline of the earth; Linnaeus had recently invented his taxonomy of organisms. So, some of the knowledge Darwin needed was in place, but other parts of the domain were wide open.

    The technology of memory is a technology of safety. What are the technologies of freedom?

    Hass read us a funny poem on story telling. The story teller was relating a myth of his people. When his listener questioned an inconsistency in his story, the story teller says, "You know, when I was a child, I used to wonder that..." Later, the listener asked the same question again, and again, and each time the story teller says, "You know, when I was a child, I used to wonder that..." When he was a child, he questioned the stories, but as he grew older -- and presumably wiser -- he came to accept the stories as they were, to retell them without question.

    We continue to tell our stories for their comfort. They make us feel safe.

    They is a danger in safety, as it can blind us to the value of change, can make us fear change. This was one of the moments in which Hass surrendered to a cheap political point, but I began to think about the dangers inherent in the other side of the equation, freedom. What sort of blindness does freedom lead us to?

    Software people and poets have something in common, in the realm of creativity: We both fall in love with patterns, with the interplay between the constant and the variable, with infinite permutation. In computing, we have the variable and the value, the function and the parameter, the framework and the plug-in. We extend and refactor, exposing the constant and the variable in our problem domains.

    Hass repeated an old joke, "Spit straight up and learn something." We laugh, a mockery of people stuck in same old patterns. This hit me right where I live. Yesterday at the closing panel of the Educators' Symposium, Joe Bergin said something that I wrote about a while back: CS educators are an extremely conservative lot. I have something to say about that panel, soon...

    First safety, then freedom -- and with it the power to innovate.

    Of course, extreme danger, pressure, insecurity can also be the necessity that leads to the creative act. As is often the case, opposites turn out to be true. As Thomas Mann said,

    A great truth is a truth whose opposite is also a great truth.

    Hass reminds us that there is agony in creativity -- a pain at stuckness, found in engagement with the world. Pain is unlike pleasure, which is homeostatic ("a beer and ballgame"). Agony is dynamic, ceasing to cling to safe position. There is always an element of anxiety, consciousness heightened at the moment of insight, gestalt in face of incomplete pattern.

    The audience asked a couple of questions:

    • Did he consult only men in his study of creativity? Yes, all but his wife, who is also a poet. She said, "Tell them to have their own strangest thoughts." What a great line.

    • Is creativity unlimited? Limitation is essential to creativity. If our work never hits an obstacle, then we don't know when it's over. (Sounds like test-driven development.) Creativity is always bouncing up against a limit.

    I'll close my report with how Hass closed the main part of his talk. He reached "the whole point of his talk" -- a sonnet by Michelangelo -- and he didn't have it in his notes!! So Hass told us the story in paraphrase:

    The pain is unbearable, paint dripping in my face, I climb down to look at it, and it's horrible, I hate it, I am no painter...

    It was the ceiling of the Sistine Chapel.

    ~~~~~

    UPDATE (10/20/05): Thanks again to Google, I have tracked down the sonnet that Hass wanted to read. I especially love the ending:

    Defend my labor's cause,
    good Giovanni, from all strictures:
    I live in hell and paint its pictures.

    -- Michelangelo Buonarroti

    I have felt this way about a program before. Many times.


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

    October 17, 2005 9:54 PM

    OOPSLA Day 2: Morning at The Educators' Symposium

    This was my second consecutive year to chair the OOPSLA Educators' Symposium, and my goal was something more down to earth yet similar in flavor: encouraging educators to consider Big Change. Most of our discussions in CS education are about how to do the Same Old Thing better, but I think that we have run the course with incremental improvements to our traditional approaches.

    We opened the day with a demonstration called Agile Apprenticeship in Academia, wherein two professors and several students used a theatrical performance to illustrate a week in a curriculum built almost entirely on software apprenticeship. Dave West and Pam Rostal wanted to have a program for developing software developers, and they didn't think that the traditional CS curriculum could do the job. So they made a Big Change: they tossed the old curriculum and created a four-year studio program in which students, mentors, and faculty work together to create software and, in the process, students learn how to do create software.

    West and Rostal defined a set of 360 competencies that students could satisfy at five different levels. Students qualify to graduate from the program by satisfying each competency at at least the third level (the ability to apply the concept in a novel situation) and some number at higher levels. Students also have to complete the standard general education curriculum of the university.

    Thinking back to yesterday's morning session at Extravagaria, we talked the role of fear and pressure in creativity. West and Rostal put any fear behind them and acted on their dream. Whatever difficulties they face in making this idea work over the long run in a broader setting -- and I believe that the approach faces serious challenges -- at least they have taken a big step forward could make something work. Those of us who don't take any big steps forward are doomed to remain close to where we are.

    I don't have much to say about the paper sessions of the day except that I noticed a recurring theme: New ideas are hard on instructors. I agree, but I do not think that they are hard in the NP-hard sense but rather in the "we've never done it that way before" sense. Unfamiliarity makes things seem hard at first. For example, I think that the biggest adjustment most professors need to make in order to move to the sort of studio approach advocated by West and ROstal is from highly-scripted lectures and controlled instructional episodes to extemporaneous lecturing in response to student needs in real-time. The real hardness in this is that faculty must have a deep, deep understanding of the material they teach -- which requires a level of experience doing that many faculty don't yet have.

    This idea of professors as practitioners, as professionals practiced in the art and science we teach, will return in later entries from this conference...

    Like yesterday's entry, I'll have more to say about today's Educators' Symposium in upcoming entries. I need some time to collect my thoughts and to write. In particular, I'd like to tell you about Ward Cunningham's keynote address and our closing panel on the future of CS education. The panel was especially energizing but troubling at the same time, and I hope to share a sense of both my optimism and my misgivings.

    But with the symposium over, I can now take the rest of the evening to relax, then sleep, have a nice longer run, and return to the first day of OOPSLA proper free to engage ideas with no outside encumbrances.


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

    October 16, 2005 9:52 PM

    OOPSLA Day 1: The Morning of Extravagaria

    OOPSLA 2005 logo

    OOPSLA has arrived, or perhaps I have arrived at OOPSLA. I almost blew today off, for rest and a run and work in my room. Some wouldn't have blamed me after yesterday, which began at 4:42 AM with a call from Northwest Airlines that my 7:05 AM flight had been cancelled, included my airline pilot missing the runway on his first pass at the San Diego airport, and ended standing in line for two hours to register at my hotel. But I dragged myself out of my room -- in part out of a sense of obligation to having been invited to participate, and in part out of a schoolboy sense of propriety that I really ought to go to the events at my conferences and make good use of my travels.

    My event for the day was an all-day workshop called Extravagaria III: Hunting Creativity. As its title reveals, this workshop was the third in a series of workshops initiated by Richard Gabriel a few years ago. Richard is motivated by the belief that computer science is in the doldrums, that what we are doing now is mostly routine and boring, and that we need a jolt of creativity to take the next Big Step. We need to learn how to write "very large-scale programs", but the way we train computer scientists, especially Ph.D. students and faculty, enforce a remarkable conservatism in problem selection and approach. The Extravagaria workshops aim to explore creativity in the arts and sciences, in an effort to understand better what we mean by creativity and perhaps better "do it" in computer science.

    The workshop started with introductions, as so many do, but I liked the twist that Richard tossed in: each of us was to tell what was the first program we ever wrote out of passion. This would reveal something about each of us to one another, and also perhaps recall the same passion within each storyteller.

    My first thought was of a program I wrote as a high school junior, in a BASIC programming course that was my first exposure to computers and programs. We wrote all the standard introductory programs of the day, but I was enraptured with the idea of writing a program to compute ratings for chessplayers following the Elo system used for chessplayers. This was much more complex than the toy problems I solved in class, requiring input in the form of player ratings and a crosstable showing results of games among the players and output in the form of updated ratings for each player. It also introduced new sorts of issues, such as using text files to save state between runs and -- even more interesting to me -- the generation of an initial set of ratings through a mechanism of successive approximations, process that may never quite converge unless we specified an epsilon larger than 0. I ultimately wrote a program of several hundred lines, a couple of orders of magnitude larger than anything I had written before. And I cared deeply about my program, the problem it solved, and its usefulness to real people.

    I enjoyed everyone else's stories, too. They reminded us all about the varied sources of passion, and how a solving a problem can open our eyes to a new world for us to explore. I was pleased by the diversity of our lot, which included workshop co-organizer John Gribble, a poet friend of Richard's who has never written a program; Rebecca Rikner, the graphic artist who designed the wonderful motif for Richard's book Writers' Workshops and the Work of Making Things, and Guy Steele, one of the best computer scientists around. The rest of us were computer science and software types, including one of my favorite bloggers, Nat Pryce. Richard's first passionate program was perhaps a program to generate "made-up words" from some simple rules, to use in naming his rock-and-roll-band. Guy offered three representative, if not first, programs: a Lisp interpreter written in assembly language, a free verse generator written in APL, and low chart generator written in RPG. This wasn't the last mention of APL today, which is often the sign of a good day.

    Our morning was built around an essay written by John Gribble for the occasion, called "Permission, Pressure, and the Creative Process". John read his essay, while occasionally allowing us in the audience to comment on his remarks or previous comments. John offered as axioms two beliefs that I share with him:

    • that all people are creative, that is, possess the potential to act creatively, and
    • that there is no difference of kind between creativity in the arts and creativity in the sciences.

    What the arts perhaps offer scientists is the history and culture of examining the creative process. We scientists and other analytical folks tend to focus on product, often to the detriment of how well we understand how we create them.

    John quoted Stephen King from his book On Writing, that the creator's job is not to find good ideas but to recognize them when they come along. For me, this idea foreshadows Ward Cunningham's keynote address at tomorrow's Educators' Symposium. Ward will speak on "nurturing the feeble simplicity", on recognizing the seeds of great ideas despite their humility and nurturing them into greatness. As Brian Foote pointed out later in the morning, this sort of connection is what makes conferences like OOPSLA so valuable and fun -- plunk yourself down into an idea-rich environment, soak in good ideas from good minds, and your own mind has the raw material it needs to make connections. That's a big part of creativity!

    John went on to assert that creativity isn't rare, but rather so common that we are oblivious to it. What is rare is for people to act on their inspirations. Why do we not act? We have so low an opinion of our selves that we figure the inspiration isn't good enough or that we can't do it justice in our execution. Another reason: We fear to fail, or to look bad in front of our friends and colleagues. We are self-conscious, and the self gets in the way of the creative act.

    Most people, John believes, need permission to act creatively. Most of us need external permission and approval to act, from friends or colleagues, peers or mentors. This struck an immediate chord with me in three different relationships: student and teacher, child and parent, and spouse and spouse. The discussion in our workshop focused on the need to receive permission, but my immediate thought was of my role as potential giver of permission. My students are creative, but most of them need me to give them permission to create. They are afraid of bad grades and of disappointing me as their instructor; they are self-conscious, as going through adolescence and our school systems tend to make them. My young daughters began life unself-conscious, but so much of their lives are about bumping into boundaries and being told "Don't do that." I suspect that children grow up most creative in an environment where they have permission to create. (Note that this is orthogonal to the issue of discipline or structure; more on that later.) Finally, just as I find myself needing my wife's permission to do and act -- not in the henpecked husband caricature, but in the sense of really caring about what she thinks -- she almost certainly feels the need for *my* permission. I don't know why this sense that I need to be a better giver of permission grew up so strong so quickly today, but it seemed like a revelation. Perhaps I can change my own behavior to help those around me feel like they can create what they want and need to create. I suspect that, in loosing the restrictions I project onto others, I will probably free myself to create, too.

    When author Donald Ritchie is asked how to start writing, he says, "First, pick up your pencil..." He's not being facetious. If you wait for inspiration to begin, then you'll never begin. Inspiration comes to those already involved in the work.

    Creativity can be shaped by constraints. I wrote about this idea six months or so ago in an entry named Patterns as a Source of Freedom. Rebecca suggested that for her at least constraints are essential to creativity, that this is why she opted to be a graphic designer instead of a "fine artist". The framework we operate in can change, across projects or even within a project, but the framework can free us to create. Brian recalled a song by the '80s punk-pop band Devo called Freedom Of Choice:

    freedom of choice is what you got
    then if you got it you don't want it
    seems to be the rule of thumb
    don't be tricked by what you see
    you got two ways to go
    freedom from choice is what you want

    Richard then gave a couple of examples of how some artists don't exercise their choice at the level of creating a product but rather at the level of selecting from lots of products generated less self-consciously. In one, a photographer for National Geographic, put together a pictorial article containing 22 pictures selected from 40,000 photos he snapped. In another, Francis Ford Coppolla shot 250 hours of film in order to create the 2-1/2 hour film Apocalypse Now.

    John then told a wonderful little story about an etymological expedition he took along the trail of ideas from the word "chutzpah", which he adores, to "effrontery", "presumptuous", and finally "presumption" -- to act as if something were true. This is a great way to free oneself to create -- to presume that one can, that one will, that one should. Chutzpah.

    Author William Stafford had a particular angle he took on this idea, what he termed the "path of stealth". He refused to believe in writer's block. He simply lowered his standards. This freed him to write something and, besides, there's always tomorrow to write something better. But as I noted earlier, inspiration comes to those already involved in the work, so writing anything is better than writing nothing.

    As editor John Gould once told Stephen King, "Write with the door closed. Revise with the door open." Write for yourself, with no one looking over your shoulder. Revise for readers, with their understanding in mind.

    Just as permission is crucial to creativity, so is time. We have to "make time", to "find time". But sometimes the work is on its own time, and will come when and at the rate it wants. Creativity demands that we allow enough time for that to happen! (That's true even for the perhaps relatively uncreative act of writing programs for a CS course... You need time, for understanding to happen and take form in code.)

    Just as permission and time are crucial to creativity, John said, so is pressure. I think we all have experienced times when a deadline hanging over our heads seemed to give us the power to create something we would otherwise have procrastinated away. Maybe we need pressure to provide the energy to drive the creative act. This pressure can be external, in the form of a client, boss, or teacher, or internal.

    This is one of the reasons I do not accept late work for a grade in my courses; I believe that most students benefit from that external impetus to act, to stop "thinking about it" and commit to code. Some students wait too long and reach a crossover point: the pressure grows quite high, but time is too short. Life is a series of balancing acts. The play between pressure and time is, I think, fundamental. We need pressure to produce, but we need time to revise. The first draft of a paper, talk, or lecture is rarely as good as it can be. Either I need to give myself to create more and better drafts, or -- which works better for me -- I need to find many opportunities to deliver the work, to create multiple opportunities to create in the small through revision, variation, and natural selection. This is, I think, one of the deep and beautiful truths embedded in extreme programming's cycle "write a test, write code, and refactor".

    Ultimately, a professional learns to rely more on internal pressure, pressure applied by the self for the self, to create. I'm not talking about the censoriousness of self-consciousness, discussed earlier, which tells us that what we produce isn't good enough -- that we should not act, at least in the current product. I'm talking about internal demands that we act, in a particular way or time. Accepting the constraints of a form -- say, the line and syllable restrictions of haiku, or the "no side effects" convention of functional programming style -- puts pressure on us to act in a way, whether it's good or bad. John gave us two other kinds of internal pressure, ones he applies to himself: the need to produce work to share at his two weekly writers' workshops, and the self-discipline of submitting work for publication every month. These pressures involve outside agents, but they are self-imposed, and require us do something we might otherwise not.

    John closed with a short inspiration. Pay attention to your wishes and dreams. They are your mind's way of telling you to do something.

    We spent the rest of the morning chatting as a group on whatever we were thinking after John's talk. Several folks related an experience well-known to any teacher: someone comes to us asking for help with a problem and, in the act of explaining the problem to us they discover the answer for themselves. Students do this with me often. Is the listener essential to this experience, or could we just ask if we were speaking to someone? I suspect that another person is essential for this to work for the learner, both because having a real person to talk to makes us explain things (pressure!) and because the listener can force us to explain the problem more clearly ("I don't understand this yet...")

    A recurring theme of the morning was the essential interactivity of creativity, even when the creator works fundamentally alone. Poets need readers. Programmers need other folks to bounce ideas off of. Learners need someone to talk to, if only to figure things out for themselves. People can be sources of ideas. They can also be reflectors, bouncing our own ideas back at us, perhaps in a different form or perhaps the same, but with permission to act on them. Creativity usually comes in the novel combination of old ideas, not truly novel ideas.

    This morning session was quite rewarding. My notes on the whole workshop are, fittingly, about half over now, but this article has already gotten quite long. So I think I'll save the afternoon sessions for entries to come. These sessions were quite different from the morning, as we created things together and then examined our processes and experiences. They will make fine stand-alone articles that I can write later -- after I break away for a bite at the IBM Eclipse Technology Exchange reception and for some time to create a bit on my own for what should take over my mind for a few hours: tomorrow's Educators' Symposium, which is only twelve hours and one eight- to ten-mile San Diego run away!


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

    October 11, 2005 6:54 PM

    Something New Every Day

    I'm not a Way Old-Timer, but I have been teaching at my current university for thirteen years. In that time, I have seen a lot of odd student programs: wacky bugs, quirky algorithms, outlandish hacks, and just plain funny code. But today I saw a new one...

    One of my colleagues is teaching our intro majors course. In the lab today, he asked students to write some code, including a three-argument Java method to return the minimum of the three. The goal of this exercise was presumably to test the students' ability to consider multiple decisions, to write compound boolean expressions, and most probably to write nested if statements.

    Here is my rendition of one student's extraordinary solution:

        public int min( int x, int y, int z )
        {
            for (int i = Integer.MIN_VALUE; i <= Integer.MAX_VALUE; i++)
                if ( i == x )
                    return x;
                else if ( i == y )
                    return y;
                else if ( i == z )
                    return z;
        }
    

    Sadly, the student didn't do this quite right, as right would be for this approach. The program did not use Integer.MIN_VALUE and Integer.MAX_VALUE to control its loop; it used hardcoded negative and positive 2,000,000,000. As a result, it had to throw in a back-up return statement after the for-loop to handle cases where the absolute of all three numbers were greater than 2,000,000,000. So, the solution loses points for correctness, and a bit of luster on style.

    But still -- wow. No matter what instructors think their students will think, the students can come up with something out of left field.

    I have to admit... In a certain way, I admire this solution. It demonstrates creativity, and even applies a pattern that works well in other contexts. If the student had been asked to write a method to find the smallest value in a three-element unsorted array, then brute force would not only have seemed like a reasonable thing to do; it would have been the only option. Why not try it for ints? (For us XP mavens: Is this algorithm the simplest thing that will work?)

    One answer to the "Why not?" question comes at run time. This method uses 12 seconds or so on average to find its answer. That's almost 12 seconds more than an if-based solution uses. :-)

    Students can bring a smile to an instructors face most every day.


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

    October 06, 2005 6:48 PM

    More Mathematics, More Coincidence

    When I started writing my recent piece on math requirements for CS degrees, I had intended to go in a different direction than the piece ultimately went. My original plan was to discuss how it is that students who do take courses like algebra in high school still seem so uncomfortable or ill-prepared to do basic arithmetic in their CS courses. But a related thread on the SIGCSE mailing list took my mind, and so the piece, elsewhere. You know what they say... You never know what you will write until you write.

    So I figured I would try to write an article on my original topic next. Again before I could write it, another math coincidence occurred, only this time nearer to my intended topic. I read Tall, Dark, and Mysterious's detailed exploration of the same problem. She starts by citing a survey that found 40% of university professors believe that *most* of their students lack "the basic skills for university-level work", explores several possible causes of the problem, and then discusses in some detail what she believes the problem to be: an emphasis in education these days on content over skill. I think that this accounts for at least part of the problem.

    Whether we overemphasize content at the expense of skill, though, I think that there is another problem at play. Even when we emphasize skill, we don't always require that students master the skills that they learn.

    For many years, I had a short article hanging on my office wall that asked the question: What is the difference between a grade of C and a grade of A in a course? Does it mean that a C student has learned less content than the A student? The same content, but not as deeply? Something else?

    Several popular jokes play off this open question. Do you want your medical doctor to have been a C student? Your lawyer? The general leading your army into battle?

    In my experience as a student and educator, the difference between a C and an A indicates different things depending on the teacher involved and, to a lesser extent, the school involved. But it's not clear to me that even for these teachers and schools the distinction is an intentional one, or that the assigned grades always reflect what is intended.

    Learning theory gives us some idea of how we might assign grades that reflect meaningful distinctions between different levels of student performance. For example, Bloom's taxonomy of educational objectives includes six levels of of learning: knowledge, comprehension, application, analysis, synthesis, and evaluation. These levels give us a way to talk about increasingly more masterful understanding and ability. Folks in education have written a lot in this sphere of discussion which, sadly, I don't know as well as I probably should. Fortunately, some CS educators have begun to write articles applying the idea to computer science curricula. We are certainly better off if we are thinking explicitly about what satisfactory and unsatisfactory performance means in our courses, and in our curricula overall.

    I heard about an interesting approach to this issue this morning at a meeting of my college's department heads. We were discussing the shortcomings of a course-by-course approach to assessing the learning outcomes of our university's liberal arts core, which purports by cumulative effect to create well-rounded, well-educated thinkers. One head described an assessment method she had read about in which the burden was shifted to the student. In this method, each student was asked to offer evidence that they had achieved the goal of being a well-rounded thinker. In effect, the student was required to "prove" that there were, in fact, educated. If we think in terms of the Bloom taxonomy discussed above, each student would have to offer evidence of that they had reached each of the six cognitive levels of maturity. Demonstrating knowledge might be straightforward, but what of comprehension, application, analysis, synthesis, and evaluation? Students could assemble a portfolio of projects, the development of which required them to comprehend, apply, analyze, synthesize, and evaluate.

    This reminded me very much of how my architecture friends had to demonstrate their readiness to proceed to the next level of the program, and ultimately to graduate: through a series of juried competitions. These projects and their juried evaluation fell outside the confines of any particular course. I think that this would be a marvelous way for computer science students, at least the ones focused on software development as a career path, to demonstrate their proficiency. I have been able to implement the idea only in individual courses, senior-level project courses required of all our majors. The result has been some spectacular projects in the intelligent systems area, including one I've written about before. I've also seen evidence that some of our seniors manage to graduate without having achieved a level of proficiency I consider appropriate. As one of their instructors, I'm at least partly responsible for that.

    This explains why I am so excited about one of the sessions to be offered as a part of the upcoming Educators Symposium at OOPSLA 2005. The session is called Apprenticeship Agility in Academia. Dave West and Pam Rostal, formerly of New Mexico Highlands University, will demonstrate "a typical development iteration as practiced by the apprentices of the NMHU Software Development Apprenticeship Program". This apprenticeship program was an attempt to build a whole software development curriculum on the idea that students advance through successive levels of knowledge and skill mastery. Students were able to join projects based on competencies already achieved and the desire to achieve further competencies offered by the projects. Dave and his folks enumerated all of the competencies that students must achieve prior to graduation, and students were then advanced in the program as they achieved them at successive levels of mastery. It solves the whole "C grade versus A grade" problem by ignoring it, focusing instead on what they really wanted students to achieve.

    Unfortunately, I have to use the past tense when describing this program, because NMHU canceled the program -- apparently for reasons extraneous to the quality or performance of the program. But I am excited that someone had the gumption and an opportunity to try this approach in practice. I'd love to see more schools and more CS educators try to integrate such ideas into their programs and courses. (That's one of the advantages of chairing an event like the OOPSLA Educators Symposium... I have some ability to shape or direct the discussion that educators have at the conference.)

    For you students out there: To what extent do you strive for mastery of the skills you learn in your courses? When do you settle for less, and why? What can you do differently to help yourselves become effective thinkers and practitioners?

    For you faculty out there: To what extent do you focus your teaching and grading efforts on student mastery of skills? What techniques work best, and why? When doyou settle for less, and why? I myself know that I settle for less all too often, sometimes due to the impediments placed in my way by our curriculum and university structure, but sometimes due to my own lack of understanding or even laziness. Staying in an intellectual arena in which I can learn from others such as West and Rostal is one way I encourage myself to think Big Thoughts and try to do better.


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

    September 29, 2005 6:27 PM

    What He Said

    Every once in a while, someone says something that just makes me say, "Oh, yeah" -- even if I've already written a similar piece myself. From The Fishbowl:

    Programming is...

    Programming is looking at a feature request in the morning, thinking, "I can do that in one line of code", and then six hours later having refactored the rest of the codebase sufficiently that you can implement the feature...

    ...in one line of code.

    That makes a nice complement to the quote from Jason Marshall and the epigram from Brian Foote quoted in my earlier post. It may have to go on to my office door.


    Posted by Eugene Wallingford | Permalink | Categories: Software Development

    September 29, 2005 1:49 PM

    Mathematics Coincidence

    An interesting coincidence... Soon after I post my spiel on preparing to study computer science, especially the role played by mathematics courses, the folks on the SIGCSE mailing list have started a busy thread on the place of required math courses in the CS curriculum. The thread began with a discussion of differential equations, which some schools apparently still require for a CS degree. The folks defending such math requirements have relied on two kinds of argument.

    One is to assert that math courses teach discipline and problem-solving skills, which all CS students need. I discussed this idea in my previous article. I don't think there is much evidence that taking math courses teaches students problem-solving skills or discipline, at least not as most courses are taught. They do tend to select for problem-solving skills and discipline, though, which makes them handy as a filter -- if that's what you want. But they are not always helpful as learning experiences for students.

    The other is to argue that students may find themselves working on scientific or engineering projects that require solving differential equations, so the course is valuable for its content. My favorite rebuttal to this argument came from a poster who listed a dozen or so projects that he had worked on in industry over the years. Each required specific skills from a domain outside computing. Should we then require one or more courses from each of those domains, on the chance that our students work on projects in them? Could we?

    Of course we couldn't. Computing is a universal tool, so it can and usually will be applied everywhere. It is something of a chameleon, quickly adaptable to the information-processing needs of a new discipline. We cannot anticipate all the possible applications of computing that our students might encounter any more than we can anticipate all the possible applications of mathematics they might encounter.

    The key is to return to the idea that underlies the first defense of math courses, that they teach skills for solving problems. Our students do need to develop such skills. But even if students could develop such skills in math courses, why shouldn't we teach them in computing courses? Our discipline requires a particular blend of analysis and synthesis and offers a particular medium for expressing and experimenting with ideas. Computer science is all about describing what can be systematically described and how to do so in the face of competing forces. The whole point of an education in computing should be to help people learn how to use the medium effectively.

    Finally, Lynn Andrea Stein pointed out an important consideration in deciding what courses to require. Most of my discussion and the discussion on the SIGCSE mailing list has focused on the benefits of requiring, say, a differential equations course. But we need also to consider the cost of such a requirement. We have already encountered one: an opportunity cost in the form of people. Certain courses filter out students who are unable to succeed in that course, and we need to be sure that we are not missing out on students who would make good computer science student. For example, I do not think that a student's inability to succeed in differential equations means that the student cannot succeed in computer science. A second opportunity cost comes in the form of instructional time. Our programs can require only so many courses, so many hours of instruction. Could we better spend a course's worth of time in computing on a topic other than differential equations? I think so.

    I remember learning about opportunity cost, in an economics course I took as an undergrad. Taking a broad set of courses outside of computing really can be useful.


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

    September 27, 2005 7:10 PM

    Preparing to Study Computer Science

    Yesterday, our department hosted a "preview day" for high school seniors who are considering majoring in computer science here at UNI. During the question-and-answer portion of one session, a student asked, "What courses should we take in our senior year to best prepare to study CS?" That's a good question, and one that resulted in a discussion among the CS faculty present.

    For most computer science faculty, the almost reflexive answer to this question is math and science. Mathematics courses encourage abstract thinking, attention to detail, and precision. Science courses help think like an empiricist: formulating hypotheses, designing experiments, making and recording observations, and drawing inferences. A computer science student will use all of these skills throughout her career.

    I began my answer with math and science, but the other faculty in the room reacted in a way that let me know they had something to say, too. So I let them take the reins. All three downplayed the popular notion that math, at least advanced math, is an essential element of the CS student's background.

    One faculty member pointed out the students with backgrounds in music often do very well in CS. This follows closely with the commonly-held view that music helps children to develop skill at spatial and symbolic reasoning tasks. Much of computing deals not with arithmetic reasoning but with symbolic reasoning. As an old AI guy, I know this all too well. In much the same way that music might help CS students, studying language may help students to develop facility manipulating ideas and symbolic representations, skills that are invaluable to the software developer and the computing researcher alike.

    We ended up closing our answer to the group by saying that studying whatever interests you deeply -- and really learning that discipline -- will help you prepare to study computer science more than following any blanket prescription to study a particular discipline.

    (In retrospect, I wish I had thought to tack on one suggestion to our conclusion: There can be great value in choosing to study something that challenges you, that doesn't interest you as much as everything else, precisely because it forces you to grow. And besides, you may find that you come to understand the something well enough to appreciate it, maybe even like it!)

    I certainly can't quibble with the direction our answer went. I have long enjoyed learning from writers, and I believe that my study of language and literature, however narrow, has made me a better computer scientist. I have had many CS students with strong backgrounds in art and music, including one wrote about last year. Studying disciplines other than math and science can lay a suitable foundation for studying computer science.

    I was surprised by the strength of the other faculty's reaction to the notion that studying math is among the best ways to prepare for CS. One of these folks was once a high school math teacher, and he has always expressed dissatisfaction with mathematics pedagogy in the US at both the K-12 and university levels. To him, math teaching is mostly memorize-and-drill, with little or no explicit effort put into developing higher-order thinking skills for doing math. Students develop these skills implicitly, if at all, through sheer dint of repetition. In his mind, the best that math courses can do for CS is to filter out folks who have not yet developed higher-order thinking skills; it won't help students develop them.

    That may well be true, though I know that many math teachers and math education researchers are trying to do more. But, while students may not need advanced math courses to succeed in CS -- at least not in many areas of software development -- they do need to master some basic arithmetical skills. I keep thinking back to a relatively straightforward programming assignment I've given in my CS II course, to implement Nick Parlante's NameSurfer nifty assignment in Java. A typical NameSurfer display looks like this image, from Nick's web page:

    As the user resizes the window, the program should grow or shrink its graph accordingly. To draw this image, the student must do some basic arithmetic to lay out the decade lines and to place the points on the lines and the names in the background. To scale the image, the student must do this arithmetic relative to window size, not with fixed values.

    Easy, right? When I assigned this program, many students reacted as if I had cut off one of their fingers. Others seemed incapable of constructing the equations needed to do scaling correctly. (And you should have the reaction students had when once, many years ago, I asked students to write a graphical Java version of Mike Clancy's delicious Cat And Mouse nifty assignment. Horror of horror -- polar coordinates!)

    This isn't advanced math. This is algebra. All students in our program were required to pass second-year algebra before being admitted to our university. But passing a course does not require mastery, and students find themselves with a course on their transcript but not the skills that the course entails.

    Clearly, mastery of basic arithmetic skills is essential to most of computer science, even if more advanced math, even calculus, are not essential. Especially when I think of algebraic reasoning more abstractly, I have hard time imagining how students can go very far in CS without mastering algebraic reasoning. Whatever its other strengths or weaknesses the How to Design Programs approach to teaching programming does one thing well, and that is to make an explicit connection between algebraic reasoning and programs. The result is something in the spirit of Polya's How to Solve It.

    This brings us back to what is the weakest part of the "math and science" answer to our brave high school student's question. So much of computing is not theory or analysis but design -- the act of working out the form of a program, interface, or system. While we may talk about the "design" of a proof or scientific experiment, we mean something more complex when we talk about the design of software. As a result, math and science do relatively little to help students develop the design skills which will be so essential to succeeding in the software side of CS.

    Studying other disciplines can help, though. Art, music, and writing all involve the students in creating things, making them think about how to make. And courses in those disciplines are more likely to talk explicitly about structure, form, and design than are math and science.

    So, we have quite defensible reasons to tell students to study disciplines other than science and math. I would still temper my advice by suggesting that students study both math and science and literature, music, art, and other creative disciplines. While this may not be what our student was looking for, perhaps the best answer is all of the above.

    Then again, maybe success in computing is controlled by aptitude, than by learning. If that is the case, then many of us, students and faculty alike, are wasting a lot of time. But I don't think that's true for most folks. Like Alan Kay, I think we just need to understand better this new medium that is computing so that we can find the right ways to empower as many people as possible to create new kinds of artifact.


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

    September 23, 2005 7:26 PM

    Ruby Friday

    I have written about Scheme my last two times out, so I figured I should give some love to another of my favorite languages.

    Like many folks these days, I am a big fan of Ruby. I took a Ruby tutorial at OOPSLA several years ago from Dave Thomas and Andy Hunt, author of the already-classic Programming Ruby. At the time, the only Ruby interpreter I could find for Mac OS 9 was a port written by a Japanese programmer, almost of whose documentation was written in, you guessed, Japanese. But I made it run and learned how to be functional in Ruby within a few hours. That told me something about the language.

    (Recalling these tutorial reminds me of two things. One, Dave and Andy give a great tutorial. If you get the chance, learn from them in person. The same can be sai for many OOPSLA tutorials. Two, thank you, Apple, for OS X as a Unix -- and for shipping it with such a nice collction of programming tools.)

  • If you want to augment the Pragmatic Programmers' guide to Ruby, check out Why's (Poignant) Guide to Ruby. You can learn Ruby there, plus quite a bit on programming more generally. You could have some fun, too.

  • Unlike many dynamic language fans, I like Java just fine. I can enjoy programming in Java, but there is no question that it gets in my way more than a language like Scheme or Ruby.

    Still, I feel compelled to share this opportunity to improve your geekware collection:

    Java Rehabilitation Clinic

    Thanks to the magic of CafePress.com, you can buy a variety of merchandise in the Java Rehab line. But why?

    Java coding need not be a life-long debilitation. With the proper treatment, and a copy of Programming Ruby, you can return to a life of happy, productive software development.

    So, give yourself over to a higher power! Learn Ruby...

    Just imagine how much more fun Java would be if it gave itself over to the higher power of higher-order procedures...

  • Finally, a little Ruby on Ruby. Check out Sam Ruby's talk, The Case for Dynamic Languages. Sam uses Ruby to illustrate his argument that the distinction between system languages and scripting languages is slowly shrinking, as the languages we use everyday become more dynamic. Along the way, he shows the power of several ideas that have entered mainstream programming parlance only in the last decade, among them closures and higher-order procedures in the form of blocks.

    But my favorite part of Sam's talk is his sub-title:

    Reinventing Smalltalk, one decade at a time

    Paul Graham says that we are reinventing Lisp, and he has a strong case. With either language as a target, the lives of programmers can only get better. The real question is whether objects as abstractions ultimately displace functions as the starting level of abstraction for the program. Another question, perhaps more important, is whether the language-as-environment can ever displace the minimalism of the scripting language as the programmer's preferred habitat. I have a hunch that the answer to both questions will be the same.


  • Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

    September 21, 2005 8:22 PM

    Two Snippets, Unrelated?

    First... A student related this to me today:

    But after your lecture on mutual recursion yesterday, [another student] commented to me, "Is it wrong to think code is beautiful? Because that's beautiful."

    It certainly isn't wrong to think code is beautiful. Code can be beautiful. Read McCarthy's original Lisp interpreter, written in Lisp itself. Study Knuth's TeX program, or Wirth's Pascal compiler. Live inside a Smalltalk image for a while.

    I love to discover beautiful code. It can be professional code or amateur, open source or closed. I've even seen many beautiful programs written by students, including my own. Sometimes a strong student delivers something beautiful as expected. Sometimes, a student surprises me by writing a beautiful program seemingly beyond his or her means.

    The best programmers strive to write beautiful code. Don't settle for less.

    (What is mutual recursion, you ask? It is a technique used to process mutually-inductive data types. See my paper Roundabout if you'd like to read more.)

    The student who told me the quote above followed with:

    That says something about the kind of students I'm associating with.

    ... and about the kind of students I have in class. Working as an academic has its advantages.

    Second... While catching up on some blog reading this afternoon, I spent some time at Pragmatic Andy's blog. One of his essays was called What happens when t approaches 0?, where t is the time it takes to write a new application. Andy claims that this is the inevitable trend of our discipline and wonders how it will change the craft of writing software.

    I immediately thought of one answer, one of those unforgettable Kent Beck one-liners. On a panel at OOPSLA 1997 in Atlanta, Kent said:

    As speed of development approaches infinity, reusability becomes irrelevant.

    If you can create a new application in no time flat, you would never worry about reusing yesterday's code!

    ----

    Is there a connection between these two snippets? Because I am teaching a course in programming languages course this semester, and particularly a unit on functional programming right now, these snippets both call to mind the beauty in Scheme.

    You may not be able to write networking software or graphical user interfaces using standard Scheme "out of the box", but you can capture some elegant patterns in only a few lines of Scheme code. And, because you can express rather complex computations in only a few lines of code, the speed of development in Scheme or any similarly powerful language approaches infinity much faster than does development in Java or C or Ada.

    I do enjoy being able to surround myself with the possibility of beauty and infinity each day.


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

    September 15, 2005 8:10 PM

    Technology and People in a Flat World

    Technology based on the digital computer and networking has radically changed the world. In fact, it has changed what is possible in such a way that how we do business and entertain ourselves in the future may bear little resemblance to what we do today.

    This will surely come as no surprise to those of you reading this blog. Blogging itself is one manifestation of this radical change, and many bloggers devote much of their blogging to discussing how blogging has changed the world (ad nauseam, it sometimes seems). But even without blogs, we all know that computing has redefined the parameters within each information is created and shared, and defined a new medium of expression that we and the computer-using world have only begun to understand.

    Thomas Friedman

    Last night, I had the opportunity to hear Thomas Friedman, Pulitzer Prize-winning international affairs columnist for the New York Times, speak on the material in his bestseller, The World Is Flat: A Brief History of the Twenty-First Century. Friedman's book tells a popular tale of how computers and networks have made physical distance increasingly irrelevant in today's world.

    Two caveats up front. The first is simple enough: I have not read the book The The World Is Flat yet, so my comments here will refer only to the talk Friedman delivered here last night. I am excited by the ideas and would like to think and write about them while they are fresh in my mind.

    The second caveat is a bit touchier. I know that Friedman is a political writer and, as such carries with him the baggage that comes from at least occasionally advocating a political position in his writing. I have friends who are big fans of his work, and I have friends who are not fans at all. To be honest, I don't know much about his political stance beyond my friends' gross characterizations of him. I do know that he has engendered strong feelings on both sides of the political spectrum. (At least one of his detractors has taken the time to create the Anti-Thomas Friedman Page -- more on that later.) I have steadfastly avoided discussing political issues in this blog, preferring to focus on technical issues, with occasional drift into the cultural effects of technology. This entry will not be an exception. Here, I will limit my comments to the story behind the writing of the book and to the technological arguments made by Friedman.

    On a personal note, I learned that, like me, Friedman is from the American Midwest. He was born in Minneapolis, married a girl from Marshalltown, Iowa, and wrote his first op-ed piece for the Des Moines Register.

    The idea to write The The World Is Flat resulted as a side effect of research Friedman was doing on another project, a documentary on off-shoring. He was interviewing Narayana Murthy, chairman of the board at Infosys, "the Microsoft of India", when Murthy said, "The global economic playing field is being leveled -- and you Americans are not ready for it." Friedman felt as if he had been sideswiped, because he considers himself well-studied in modern economics and politics, and he didn't know what Murthy meant by "the global economic playing field is being leveled" or how we Americans were so glaringly unprepared.

    As writers often do, Friedman set out to write a book on the topic in order to learn it. He studied Bangalore, the renown center of the off-shored American computing industry. Then he studies Dalien, China, the Bangalore of Japan. Until last night, I didn't even know such a place existed. Dalyen plays the familiar role. It is a city of over a million people, many of whom speak Japanese and whose children are now required to learn Japanese in school. They operate call centers, manage supply chains, and write software for japanese companies -- all jobs that used to be done in Japan by Japanese.

    Clearly the phenomenon of off-shoring is not US-centric. Other economies are vulnerable. What is the dynamic at play?

    Friedman argues that we are in a third era of globalization. The first, which he kitschily calls Globalization 1.0, ran from roughly 1492, roughly when Europe began its imperial expansion across the globe, to the early 1800s. In this era, the agent of globalization was the country. Countries expanded their land holdings and grew their economies by reaching overseas. The second era ran from the early 1800s until roughly 2000. (Friedman chose this number as a literary device, I think... 1989 or 1995 would have made better symbolic endpoints.) In this era, the corporation was the primary agent of globalization. Companies such as the British East India Company reached around the globe to do commerce, carrying with them culture and politics and customs.

    We are now in Friedman's third era, Globalization 3.0. Now, the agent of change is the individual. Technology has empowered individual persons to reach across national and continental boundaries, to interact with people of other nationalities, cultures, and faiths, and to perform commercial, cultural, and creative transactions independent of their employers or nations.

    Blogging is, again, a great example of this phenomenon. My blog offers me a way to create a "brand identity" independent of any organization. (Hosting it at www.eugenewallingford.com would sharpen the distinction!) I am able to engage in intellectual and even commercial discourse with folks around the world in much the same way I do with my colleagues here at the university. In the last hour, my blog has been accessed by readers in Europe, Australia, South America, Canada, and in all corners of the United States. Writers have always had this opportunity, but at glacial rates of exchange. Now, anyone with a public library card can blog to the world.

    Technology -- specifically networking and the digital computer -- has made Globalization 3.0 possible. Friedman breaks our current era into a sequence of phases characterized by particular advances or realizations. The specifics of his history of technology are sometimes arbitrary, but at the coarsest level he is mostly on the mark:

    1. 11/09/89 - The Berlin Wall falls, symbolically opening the the door for the East and West to communicate. Within a few months, Windows 3.0 ships, and the new accessibility of the personal computer made it possible for all of us to be "digital authors".

    2. 08/09/95 - Netscape went public. The investment craze of its IPO presaged the dot-com boom, and the resultant investment in network technology companies supplied the capital that wired the world, connecting everyone to everyone else.

    3. mid 1990s - The technology world began to move toward standards for data interchange and software connectivity. This standards movement resulted in what Friedman calls a "collaboration platform", on which new ways of working together can be built.

    These three phases have been followed in rapid succession by a number of faster-moving realizations on top of the collaboration platform:

    1. outsourcing tasks from one company to another

    2. offshoring tasks from one country to another

    3. uploading of digital content by individuals

    4. supply chaining to maximize the value of offshoring and outsourcing by carefully managing the flow of goods and services at the unit level

    5. insourcing of other companies into public interface of a company's commercial transactions

    6. informing oneself via search of global networks

    7. mobility (my term) of data and means of communication

    Uploading is the phase where blogs entered the picture. But there is so much more. Before blogs came open source software, in which individual programmers can change their software platform -- and share their advances with others but uploading code into a common repository. And before open source became popular we had the web itself. If Mark Rupert objects to what he considers Thomas Friedman's "repeated ridicule" of those opposed to globalization, then he can create a web page to make his case. Early on, academics had an edge in creating web content, but the advance of computing hardware and now software has made it possible for anyone to publish content. The blogging culture has even increased the opportunity to participate in wider debate more easily (though, as discussions of the "long tail" have shown, that effect may be dying off as the space of blogs grows beyond what is manageable by a single person).

    Friedman's description of insourcing sounded a lot like outsourcing to me, so I may need to read his book to fully get it. He used UPS and FedEx as examples of companies that do outsourced work for other corporations, but whose reach extends deeper into the core functions of the outsourcing company, intermingling in a way that sometimes makes the two companies' identities indistinguishable to the outside viewer.

    The quintessential example of informing is, of course, Google, which has made more information more immediately accessible to more people than any entity in history. It seems inevitable that, with time, more and more content will become available on-line. The interesting technical question is how to search effectively in databases that are so large and heterogeneous. Friedman explains well to his mostly non-technical audience that we are at just the beginning of our understanding of search. Google isn't the only player in this field, obviously, as Yahoo!, Microsoft, and a host of other research groups are exploring this problem space. I hold out belief that techniques from artificial intelligence will play an increasing role in this domain. If you are interested in Internet search, I suggest that you read Jeremy Zawodny's blog.

    Friedman did not have a good name for the most recent realization atop his collaboration platform, referring to it as all of the above "on steroids". To me, we are in the stage of realizing the mobility and pervasiveness of digital data and devices. Cell phones are everywhere, and usually in use by the holder. Do university students ever hang up? (What a quaint anachronism that is...) Add to this numerous other technologies such as wireless networks, voice over internet, bluetooth devices, ... and you have a time in which people are never without access to their data or their collaborators. Cyberspace isn't "out there" any more. It is wherever you are.

    These seven stages of collaboration have, in Friedman's view, engendered a global communication convergence, at the nexus of which commerce, economics, education, and governance have been revolutionized. This convergence is really an ongoing conversion of an old paradigm into a new one. Equally important are two other convergences in process. One he calls "horizontaling ourselves", in which individuals stop thinking in terms of what they create and start thinking in terms of who they collaborate with, of what ideas they connect to. The other is the one that ought to scare us Westerners who have grown comfortable in our economic hegemony: the opening of India, China, and the former Soviet Union, and 3 billion new players walking onto a level economic playing field.

    Even if we adapt to all of the changes wrought by our own technologies and become well-suited to compete in the new marketplace, the shear numbers of our competitors will increase so significantly that the market will be a much starker place.

    Friedman told a little story later in the evening that illustrates this point quite nicely. I think he attributed the anecdote to Bill Gates. Thirty years ago, would you prefer to have been born a B student in Poughkeepsie, or a genius in Beijing or Bangalore? Easy: a B student in Poughkeepsie. Your opportunities were immensely wider and more promising. Today? Forget it. The soft B student from Poughkeepsie will be eaten alive by a bright and industrious Indian or Chinese entrepreneur.

    Or, in other words from Friedman, remember: In China, if you are "1 in a million", then there are 1300 people just like you.

    All of these changes will take time, as we build the physical and human infrastructure we need to capitalize fully on new opportunities. The same thing happened when we discovered electricity. The same thing happened when Gutenberg invented the printing press. But change will happen faster now, in large part due to the power of the very technology we are harnessing, computing.

    Gutenberg and the printing press. Compared to the computing revolution. Where have we heard this before? Alan Kay has been saying much the same thing, though mostly to a technical audience, for over 30 years! I was saddened to think that nearly everyone in the audience last night thinks that Friedman is the first person to tell this story, but gladdened that maybe now more people will understand the momentous weight of the change that the world is undergoing as we live. Intellectual middlemen such as Friedman still have a valuable role to play in this world.

    As Carly Fiorina (who was recently Alan's boss at Hewlett-Packard before both were let go in a mind-numbing purge) said, "The 'IT revolution' was only a warm-up act." Who was it that said, "The computer revolution hasn't happened yet."?

    The question-and-answer session that followed Friedman's talk produced a couple of good stories, most of which strayed into policy and politics. One dealt with a topic close to this blog's purpose, teaching and learning. As you might imagine, Friedman strongly suggests education as an essential part of preparing to compete in a flat world, in particular the ability to "learn how to learn" He told us of a recent speaking engagement at which an ambitious 9th grader asked him, "Okay, great. What class do I take to learn how to learn?" His answer may be incomplete, but it was very good advice indeed: Ask all your friends who the best teachers are, and then take their courses -- whatever they teach. It really doesn't matter the content of the course; what matters is to work with teachers who love their material, who love to teach, who themselves love to learn.

    As a teacher, I think one of the highest forms of praise I can get from a student is to be told that they want to take whatever course I am teaching the next semester. It may not be in their area of concentration, or in the hot topic du jour, but they want to learn with me. When a student tells me this -- however rare that may be -- I know that I have communicated something of my love for knowledge and learning and mastery to at least one student. And I know that the student will gain just as much in my course as they would have in Buzzword 401.

    We in science, engineering, and technology may benefit from Friedman's book reaching such a wide audience. He encourages a focus not merely on education but specifically on education in engineering and the sciences. Any American who has done a Ph.D. in computer science knows that CS graduate students in this country are largely from India and the Far East. These folks are bright, industrious, interesting people, many of whom are now choosing to return to their home countries upon completion of their degrees. They become part of the technical cadre that helps to develop competitors in the flat world.

    As I listened last night, Chad Fowler's new book My Job Went to India came to mind. This is another book I haven't read yet, but I've read a lot about it on the web. My impression is that Chad looks at off-shoring not as a reason to whine about bad fortune but as an opportunity to recognize our need to improve our skills for participating in today's marketplace. We need to sharpen our technical skills but also develop our communication skills, the soft skills that enable and facilitate collaboration at a level higher than uploading a patch to our favorite open source project. Friedman, too, looks at the other side of off-shoring, to the folks in Bangalore who are working hard to become valuable contributors in a world redefined by technology. It may be easy to blame American CEOs for greed, but that ignores the fact that the world is changing right before us. It also does nothing to solve the problem.

    All in all, I found Friedman to be an engaging speaker who gave a well-crafted talk full of entertaining stories but with substance throughout. I can't recommend his book yet, but I can recommend that you go to hear him speak if you have the opportunity.


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

    September 09, 2005 12:44 PM

    Missing PLoP

    PLoP 2005 Banner

    This being Friday, September 9, I have to come to grips with the fact that I won't be participating in PLoP 2005. This is the 12th PLoP, and it would have been my 10th, all consecutively. PLoP has long been one of my favorite conferences, both for how much it helps me to improve my papers and my writing and for how many neat ideas and people I encounter there. Last year's PLoP led directly to four blog entries, on patterns as autopsy, patterns and change, patterns and myth, and the wiki of the future, not to mention a few others indirectly later. Of course, I also wrote about the wonderful running in and around Allerton Park, the pastoral setting of PLoP. I will dearly miss doing my 20-miler there this weekend...

    PLoP 2005 Banner

    Sadly, events conspired against me going to PLoP this year. The deadline for submissions fell at about the same time as the deadline for applications for the chair of my department, both of which fell around when I was in San Diego for the spring planning meeting for OOPSLA 2005. Even had I submitted, I would have had a hard time doing justice to paper revisions through the summer, as I learned the ropes of my new job. And now, new job duties make this a rather bad time to hop into the car and drive to Illinois for a few days. (Not that I wasn't tempted early in the week to drive down this morning to join in for a day!)

    I am not certain if other academics feel about some of the conferences they attend the way I feel about PLoP, OOPSLA, and ChiliPLoP, but I do know that I don't feel the same way about other conferences that I attend, even ones I enjoy. The PLoPs offer something that no other conference does: a profound concern for the quality of technical writing and communication more generally. PLoP Classic, in particular, has a right-brain feel unlike any conference I've attended. But don't think that this is a result of being overrun by a bunch of non-techies; the conference roster is usually dominated by very good minds from some of the best technical outfits in the world. But these folks are more than just techies.

    Unfortunately I'm not the only regular who is missing PLoP this year. The attendee list for 2005 is smaller than in recent years, as was the number of submissions and accepted papers. The Hillside Group is considering the future of PLoP and ChiliPLoP in light of the more mainstream role of patterns in the software world and the loss of cache that comes when one software buzzword is replaced with another. Patterns are no longer the hot buzzword -- they are a couple of generations of buzzwords beyond that -- which changes how conferences in the area need to be run. I think, though, that it is essential for us to maintain a way for new pattern writers to enter the community and be nurtured by pattern experts. It is also essential that we continue to provide a place where we care not only about the quality of technical content but also about the quality of technical writing.

    On the XP mailing list this morning, Ron Jeffries mentioned the "patterns movement":

    In the patterns movement, there was the notion of "forces". The idea of applying a pattern or pattern language was to "balance" the forces.

    I hope Ron's use of past tense was historical, in the sense that the patterns movement first emphasized the notion of forces "back then", rather than a comment that the patterns movement is over. The heyday is over, but I think we software folks still have a lot to learn about design from patterns.

    I am missing PLoP 2005. Sigh. I guess there's always ChiliPLoP 2006. Maybe I can even swing EuroPLoP next year.


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

    August 18, 2005 6:59 PM

    Embarrassed for My Discipline

    Earlier this week, I learned a bit about how to use my university's financial information system. It is an application built almost entirely out of the box using Oracle E-Business Suite tools. By the time I left the room, I was embarrassed for my discipline.

    My college secretary gave an informal tutorial to me, another new head, and our acting dean. We learned that it is not straightforward to do most of the tasks that we might want to do. What was worst, from most point of view as a software developer, is that the complexity of the interface matched or exceeded the complexity of the underlying data.

    The primary users of this system -- secretaries and office personnel -- seem to be good troopers. They acknowledge the complexity of the system with mostly good cheer and seem intent on mastering the complexity of the interface. Then again, perhaps they are just being kind when they speak to me, a "computer person", and are burning their mousepads -- and me in effigy -- when I'm not around. I wouldn't blame them.

    The administrators I've talked to, who have to use the system to manage their budgets and personnel, openly grumble about the system.

    To be fair, this software solves a very large problem in our medium-sized institution. As an undergraduate, I worked as a programmer in administrative computing at my alma mater. The database with which we worked seemed uncommonly complex at the time. Of course, it wasn't; I was just inexperienced in the ways of computing. Financial information systems these days are even more complex, managing the interactions among several classes of employees and supervisors, payroll and grants and foundation accounts, departments and units and colleges, .... On top of that are issues of security and responsiveness. I don't doubt that our financial information system is more complex than any IS with which I have worked.

    But users shouldn't have to see any more of this complexity than necessary. Users of our system seem to see nothing but complexity. Layers of jargon-laden links that serve as menus. Several cryptic codes that must be entered before you can reach data on any form. Few, if any, defaults. Few, if any, shortcuts.

    The giveaway that the system is too complex for its own good? Regular users have asked system administrators to create a "cheat sheet", a page containing advice of the sort, "If you want to see data on x, do the following..." Why can't frequent, knowledgeable users find their way to commonly-needed data already?

    The good news for users here is that the team that administers our system has produced good on-line training material. (Someone at OracleAppsBlog thinks so, too.) Good. But why should the main focus of a software unit be to produce good documentation? As we in the agile community know, the need to write better comments usually indicates the need to write better code. The need for excellent training materials implies a need for a better interface.

    I don't want to be too hard on Oracle. I know that the task is complex, and I know that Oracle isn't the only computing company producing software that users can't use, at least comfortably. This system is just one example, albeit a very good one, of a general problem in our industry. But I guess I do expect more from "the world's largest enterprise software company" ...

    And I'm certainly not complaining about the UNI folks who have assembled our information system. They built the system on a relatively small budget using standard Oracle code, interface components, and style sheets. But, as a user, I wish that we could do better.

    Even sadder in these days of budget cuts in higher education, my university has almost certainly sunk in excess of $100,000 into this system and thus are committed to the long-term costs of keeping it functional. When I add in training costs, the total cost probably goes up significantly. When I add in the cost of the time lost battling the system ... I don't want to think about it.

    We in software development do a disservice to users when we tell them, explicitly or implicitly, that things have to be complex, hard to use, uncomfortable, painful. We tell them that they don't understand. We tell them that they must just not be smart enough to use technology. We are wrong, and they should be told that.

    In thinking about concrete, relatively low cost steps we would take to improve the quality of user experience, a friend and I focused on the fact that most accesses into the system recurring. While I was being "trained", I repeatedly heard "you don't need to worry about these options. You'll never use them. Focus on this subset of options...." How about something simple, which Mac OS has had forever: an easily-accessible recent items menu? Or a "most-frequently accessed reports" menu? I am guessing that, within a few uses, most administrators would never have to venture outside one of these lists. More frequent users might need a longer list, but that's no problem.

    Upon further inspection, it seems that users of our system can build their own shortcuts lists, by "customizing" their own "portlets". (Portlet?) But I am not yet certain how to use this interface feature properly. I must not be smart enough to use this system. Maybe I don't understand. Sorry, I don't believe that -- about me or about any of the regular users of this system.

    We know how to do better. Most developers know better -- or should.


    Posted by Eugene Wallingford | Permalink | Categories: Software Development

    August 09, 2005 4:00 PM

    The Academic Future of Agile Methods

    After a week impersonating one of the Two Men and a Truck guys, I'm finally back to reading a bit. Brian Marick wrote several articles in the last week that caught my attention, and I'd like to comment on two now.

    The first talked about why Brian thinks the agile movement in software development is akin to the British cybernetics movement that began in the late 1940's. He points out three key similarities in the two:

    • a preference for performance (e.g., writing software) over representation (e.g., writing requirements documents)
    • constant adaptation to the environment as a means for achieving whole function
    • a fondness for surprises that arise when we build and play with complex artifacts

    I don't know much about British cybernetics, but I'm intrigued by the connections that Brian has drawn, especially when he says, "What I wanted to talk about is the fact that cybernetics fizzled. If we share its approaches, might we also share its fatal flaws?"

    My interest in this seemingly abstract connection would not surprise my Ph.D. advisor or any of the folks who knew me back in my grad school days -- especially my favorite philosophy professor. My research was in the area of knowledge-based systems, which naturally took me into the related areas of cognitive psychology and epistemology. My work with Dr. Hall led me to the American pragmatists -- primarily C. S. Peirce, William James, and John Dewey. I argued that the epistemology of the pragmatists, driven as it was by the instrumental value of knowledge for changing how we behave in particular contexts, was the most appropriate model for AI scientists to build upon, rather than the mathematical logic that dominates most of AI. My doctoral work on reasoning about legal arguments drew heavily on the pragmatic logic of Stephen Toulmin (whose book The Uses of Argument I strongly recommend, by the way).

    My interest in the connection between AI and pragmatic epistemology grew from a class paper into a proposed chapter in my dissertation. For a variety of reasons the chapter never made it into my dissertation, but my interest remains strong. While going through files as a part of my move last week, I came across my folder of drafts and notes on this. I would love to make time to write this up in a more complete form...

    Brian's second article gave up -- only temporarily, I hope -- on discussing how flaws in the agile movement threaten its advancement, but he did offer two suggestions for how agile folks might better ensure the long-term survival and effect o their work: produce a seminal undergraduate-level textbook and "take over a computer science department". Just how would these accomplish the goal?

    It's hard to overestimate the value of a great textbook, especially the one that reshapes how folks think about an area. I've written often about the ebbs and flows of the first course in CS and, while much of the history of CS1 can be told by tracing the changes in programming language used, perhaps more can be told by tracing the textbooks that changed CS1. I can think of several off-hand, most notably Dan McCracken's Fortran IV text and Nell Dale's Pascal text. The C++ hegemony in CS 1 didn't last long, and that may be due to the fact that no C++-based book ever caught fire with everyone. I think Rick Mercer's Computing Fundamentals with C++ made it possible for a lot of instructors and schools to teach a "soft" object-oriented form of OOP in C++. Personally, I don't think we have seen the great Java-in-CS1 book yet, though I'm sure that the small army of authors who have written Java-in-CS1 books may think differently.

    Even for languages and approaches that will never dominate CS1, a great textbook can be a defining landmark. As far as OOP in CS1 goes, I think that Conner, Nigidula, and van Dam's Object-Oriented Programming in Pascal is still the benchmark. More recently, Felleisen et al.'s How to Design Programs stakes a major claim for how to teach introductory programming in a new way. Its approach is very different from traditional CS1 pedagogy, though, and it hasn't had a galvanizing effect on the world yet.

    An agile software engineering text could allow us agile folks to teach software engineering in a new and provocative way. Many of us are teaching such courses already when we can, often in the face of opposition from the "traditional" software engineers in our departments. (When I taught my course last fall, the software engineering faculty argued strongly that the course should not count as a software engineering course at all!) I know of only agile software engineering text out there -- Steinberg and Palmer's Extreme Software Engineering -- but it is not positioned as the SE-complete text that Brian envisions.

    Closer to my own world, of course, is the need for a great patterns-oriented CS1 book of the sort some of us have been working on for a while. Such a text would almost certainly be more agile than the traditional CS1 text and so could provide a nice entry point for students to experience the benefits of an agile approach. We just haven't yet been able to put our money where our mouth is -- yet.

    On Brian's three notes:

    1. Using Refactoring and Test-Driven Development and various other readings can work well enough for an agile development course, but the need for a single text is still evident. First, having scattered materials is too much work for the more casual instructor charged with teaching "the agile course". Second, even together they do not provide the holistic view of software engineering required if this text is to convince CS faculty that it is sufficient for an introductory SE course.

    2. Yes and yes. Alternative forms of education such as apprenticeship may well change how we do some of our undergraduate curriculum, but no one should bet the survival of agile methods on the broad adoption of radically different teaching methods or curricula in the university. We are, as a whole, a conservative lot.

      That doesn't mean that some of us aren't trying. I'm chairing OOPSLA's Educators' Symposium again this year, and we are leading off our day Dave West and Pam Rostal's Apprenticeship Agility in Academia, which promises a firestorm of thinking about how to teach CS -- and software development and agility and ... -- differently.

    3. I have used Bill Wake's Refactoring Workbook as a source of lab exercises for my students. It is a great resource, as is Bill's website. But it isn't a software engineering textbook.

    Why "take over a computer science department"? To create a critical mass of agile-leaning faculty who can support one another in restructuring curricula, developing courses, writing textbook, experimenting with teaching methods, and thinking Big Thoughts. Being one among nine or 15 or 25 on a faculty means a lot of hard work selling a new idea and a lot of time isolated from the daily conversations that help new ideas to form and grow. OOPSLA and Agile 200x and SIGCSE only come once a year, after all. And Cedar Falls, Iowa, is far from everywhere when I need to have a conversation on agile software development right now. So is Raleigh, North Carolina, for that matter, when Laurie Williams could really use the sort of interaction that the MIT AI Lab has been offering AI scientists for 40 years.

    Accomplishing this takeover is an exercise left to the reader. It is a slow process, if even possible. But it can be done, when strong leaders of departments and colleges set their minds and resources to doing the job. It also requires a dose of luck.


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

    July 18, 2005 11:32 AM

    Lessons from 13 Books

    I've recently run across in several different places recommendations for Leonard Koren's Wabi-Sabi: for Artists, Designers, Poets & Philosophers, so I thought I'd give it a read. My local libraries don't have it, so I'm still waiting. While looking, though, I saw another book by Koren, called 13 Books : (Notes on the Design, Construction & Marketing of my Last...). The title was intriguing, so I looked for it in the stacks. The back cover kept my attention, so I decided to read it this weekend. It contained the opening sentences of the book:

    Authorship unavoidably implies a certain degree of expertise about the subject you are writing on. This has always troubled me because, although I have written numerous books on various subjects, I've never really considered myself an expert about anything. Recently, however, I had an encouraging realization. Surely I must know more about the making of the 13 books

    ... that he has written than anyone else! So he wrote this book, which consists of a discussion of each of his previous works, including his source of inspiration for the work, the greatest difficulty he faced in producing it, and one enduring lesson he learned from the experience.

    (This book ties back nicely to two previous entries here. First, it adds to my league-leading total for being the first reader of a book in my university library. Second, it was a gift to the library by Roy Behrens, a design professor here whose Ballast Quarterly Review I mentioned a few months ago.)

    13 Books is clearly the product of a graphic designer who likes to explore the interplay between text and graphic elements and who likes to make atypical books. It's laid out in a style that may distract some readers. But, within the self-referential narrative, I found some of Koren's insights to be valuable beyond his experience, in terms of software, creativity, and writing.

    On software

    Projects ultimately develop their own identity, at which point the creator has a limited role in determining its shape. Koren learned this when he felt compelled to include a person in one of his books, despite the fact that he didn't like the guy, because it was essential to the integrity of the project. I feel something similar when writing programs in a test-code-refactor rhythm. Whether I like a particular class or construct, sometimes I'm compelled to create or retain it. The code is telling me something about its own identity.

    Just from its brief appearance in this book, I can see how the idea of wabi-sabi found an eager audience with software developers and especially XPers. Koren defines wabi-sabi as "a beauty of things imperfect, impermanent, and incomplete... a beauty of things modest and humble..." In the face of changing requirements and user preferences, we must recognize that our software is ever-changing. If our sense of beauty is bound up in its final state, then we are destined to design software in a way that aims at a perfect end -- only to see the code break down when the world around it changes. We need a more dynamic sense of beauty, one that recognizes beauty in the work-in-progress, in the system that needs a few more features to be truly useful, in the program whose refactoring is part of its essence.

    Later in the book, Koren laments that making paper books is "retrograde" to his tech friends. He then says, "And the concept of wabi-sabi, the stated antithesis of digital this and digital that, was, by extrapolation, of negligible cultural relevance." I see no reason that wabi-sabi stands in opposition to digital creations. I sense it my programs.

    Finally, here is my favorite quote from the book that is unwittingly about software:

    The problem with bad craftsmanship is that it needlessly distracts from the purity of your communication; it draws away energy and attention; it raises questions in the reader's mind that shouldn't be there.

    Koren writes of font, layout, covers, and bindings. But he could just as easily be writing of variable names, the indentation of code, comments, ...

    On creativity and learning

    At least one of the thirteen books was inspired by Koren's rummaging through his old files, aimlessly looking at photos. We've seen this advice before, even more compellingly, in Twyla Tharp's "start with a box". (That reminds me: I've been meaning to write up a more complete essay on that book...)

    Taking on projects for reasons of perceived marketability or laziness may sometimes make sense, but not if your goal is to learn:

    The ideas for both books came too quickly and easily, and there was no subsequent concept of development. In my future books I would need to challenge myself more.

    In building software systems, in learning new languages, in adopting new techniques -- the challenge is where you grow.

    In retrospect, Koren categorized his sources of inspiration for his books. The split is instructive: 40% were the next obvious step in a process, 30% came from hard work, and 30% were the result of "epiphanies from out of the blue". This means that fully two-thirds of his books resulted from the work of of being a creator, not from a lightning bolt. Relying on flashes of inspiration is a recipe for slow progress -- probably no progress at all, because I believe that those flashes ultimately flow from the mind made ready by work.

    On writing and publishing

    Koren is a graphic designer for whom books are the preferred medium. Throughout his career, he has often been dissatisfied with power imbalance between creators and publishers. He is constantly on the look-out for a new way to publish. For many, the web has opened new avenues for publishing books, articles, and software with little or no interference from a publisher. The real-time connectedness of the web has even made possible new modes of publication such as the blog, with conversations as a medium for creating and sharing ideas in a way. Blogs are often characterized as being ephemeral and light, but I think that we'll all be referring to Martin Fowler's essays and the Pragmatic Programmers' articles on their blogs for years to come.

    While Koren may remain a bookmaker, and despite his comments against digital technology as creative medium, I think his jangling, cross-linked, quick-hit style would play well in a web site. It might be interesting to see him produce an on-line work that marries the two. Heck, it's been been done with PowerPoint.

    As someone who has been reflecting a year writing this blog, I certainly recognize the truth in this statement:

    A book need be grand neither in scale nor subject matter to find an audience.

    Waiting until I have something grand to say is a sure way to paralyze myself.

    Finally, Koren offered this as the enduring lesson he learned in producing his book Useful Ideas from Japan:

    Reducing topical information to abbreviated humorous tidbits is a road to popular cultural resonance.

    It seems that Koren has the spirit of a blogger after all.


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

    July 14, 2005 6:48 PM

    The Tipping Point for Agile Software Development

    While out running today, I had one of those flashes of inspiration -- a crystal-clear, wholly-formed thought -- for how I might introduce agile software development in an undergraduate course. In this image, we begin the first day of a course with a software project to implement. The first thing we do is work as a group to decompose the into chunks that the students believe they can implement in one day. No Planning Game jargon; just a bunch of students working with me to design the course project and the programming assignments they will have to do. On another day, we could work on one of the day-long projects, breaking it down further and writing a test for each small piece before we write any code. No TDD or JUnit jargon; just a bunch of folks writing short test programs for code they think they understand how to write.

    I'm not sure why this flash happened today. I'm not slated to teach agile software development per se for a while. The last time I taught the offers some reason that my mind would seek a new way to open the course. Then, I *talked about* agile development first, and we began to work on agile practices with test-first development first. At the end of the course, I felt as if too few of the students had grokked the idea, at least in part before they never felt motivated to give it a reasonable shot. I don't mean that the students necessarily started with a desire not to get it; rather, they never felt a strong internal desire to endure the pain of changing their habits for building software. And old habits die hard, if at all.

    This feeling brings to mind something I read a couple of weeks ago:

    People don't choose rationally to listen to your message and then have a feeling about it. They choose to listen to your message because they have a feeling about it.

    University instructors and industrial trainers should keep this thought close to their minds. The folks at Creating Passionate Users know that it is hard to spark passion in readers or product users when they have no particular feeling for the work. The same is true for many students in a course. I may be able to draw in a few students slowly over time, as things click in their minds, but for most I need to help them want to learn and know and do. This is especially true of helping people to change deeply ingrained habits,such as how they develop software.

    Then what should I read today but this quote from Malcolm Gladwell's The Tipping Point, over at Agile Advice, presented in just the context of my inspirational moment:

    ...the content of the message matters, too. And the specific quality that a message needs to be successful is the quality of "stickiness." Is the message - or the food, or the movie, or the product - memorable? Is it so memorable, in fact, that it can create change, that it can spur someone to action?

    I need to find and communicate better the stickiness of agile development. My running thought seems closer to agile development's stickiness than what I've done before.

    If my thoughts were controlled more by my rational side, I would be having flashes of inspiration for teaching my programming languages course this fall. What is the stickiness of functional programming, of Scheme? How can I shape a mindset in my students whereby they feel passion to learn these new ideas and change how they think about programs?

    Maybe I need to go for another run and cross my fingers.


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

    July 13, 2005 12:29 PM

    Comments on Talks I Didn't Hear

    One of the things I miss being at a smaller school in a less densely populated part of the country is the ability to go to stimulating research talks on a regular basis. When I was at Michigan State, I could go to a good talk in computer science or a closely related discipline frequently, if I had the time and inclination. It's hard to create that sort of environment at a school the size of UNI. One of my goals for the department this fall is to create a seminar series that draws on the research our faculty is doing, as well as research and scholarship being done at the many other schools in Northeast Iowa. I don't know if we have a critical mass of audience to sustain such a series, but I think that it's worth finding out.

    In the meantime, following other people's involvement in research talks is one solace. Andrew Birkett recently wrote about attending the Scottish Programming Languages Seminar held last month. Just reading his summary stimulated my mind a bit...

    One talk described an attempt to measure the productivity difference between static and dynamic languages, toward which Andrew was skeptical. I am, too. The difference between static and dynamic languages is at least as much one of culture and habit of thought as it is of language and tools.

    When you use a dynamic language, it's not because you have a masochistic enjoyment of finding statically-findable bugs by hand. It's because you enjoy a much more flexible overall programming experience - different toolset, and better support for "exploratory programming" as you learn about the problem domain.

    Measuring differences in productivity across cultures is tricky. In my experience, folks just end up scratching their heads at the other camp and thinking, "But that's not even a part of my universe." That said, I would be interested in evaluating an attempt to tackle this hard problem.

    Another talk centered on the notion that the purpose of type checking is, at one level, to distinguish 'good' programs from 'bad' ones, for a particular definition of those evaluative terms. In the usual sense of static typing, good programs pass the type checker, and bad programs do not. The presumption of strongly, statically typed languages is that the first step toward being a good program is passing the type checker. This presumption can get in the way sometimes. I remember my frustration when learning Haskell: I would write a mutually recursive function that executed correctly for all inputs, but the Haskell type inference system refused to accept the definition because it could not infer the types of the inductive data elements. Writing those type definitions by hand proved difficult or impossible.

    (Don't take this remark about Haskell out of context, though. It is a very cool language that can change how you think about programs -- definitely worth the energy to go learn it!)

    Defining 'good' and 'bad' programs in terms of passing a type checker is potentially a very fine thing to do, but it has important implications for how programmers think about programs and programming. What if we decided that the first step toward being a good program was something else and then designed a tool to enforce that notion? Programming might be quite different! In a sense, I think that test-driven development is an example of just this sort of thing. Passing a test is more important than making the type checker happy. Working in dynamic languages such as Scheme can feel that way, too -- the emphasis is not on types but on passing test cases.

    The talk that raised this idea about type systems went on to describe an interesting idea: creating a type checker that blends static and dynamic checks. The checker infers as much as it can statically and then leaves the rest of the type checks for run time.

    And then you can either go back and tweak your source code to provide more information, or you can go ahead and run your program, knowing that some properties have been checked statically (i.e., they are true for all possible runs of the program) and some will be checked dynamically (i.e., the program will terminate if a properties is discovered to be false).

    If Haskell had this sort of flexibility in its typing system, then I would have been more inclined to use the language as more than a learning and research vehicle.

    Now that I have mentioned Haskell a couple of times, I will close with one last comment from Andrew, about another of the talks at the seminar:

    The formal side of this talk was a little bit beyond me. I have to concentrate when people discuss Monads formally.

    I have to admit, with some sheepishness, that reading papers and listening to talks about monads have always made my head hurt. I don't know if this situation can be remedied by the right sort of practice, or if it is merely a sign of my fundamental cognitive limitations. In either case, I'm content with my state for now.


    Posted by Eugene Wallingford | Permalink | Categories: Software Development

    July 06, 2005 8:23 PM

    Too Many Variables

    Do you remember this old Billy Crystal/Christopher Guest skit from Saturday Night Live? The guys were janitors. When they ran into one another, they would take turns describing to one another accidents that had happened to them. The first incidents in the exchange were the sort that could happen to a working guy, such as "You know when you're working in the shop and you hit your thumb with a hammer?" But as the skit progresses, the accidents become incidents of strange, self-inflicted pain that could never happen accidentally, such as "You know when stick your inside your car door and just slam the door right on your head? That really hurts." The unforgettable catch phrase of the skit was this classic: "I *hate* when that happens."

    Interval training on a track can be like that. I imagine most non-runners listening to me tell tales of my track work-outs and thinking of me the way we all thought of Guest and Crystal at the end of their skits. "I *hate* when that happens." Well, duh. It's all quite funny, unless your the guy with his head crushed by the car door.

    When I run intervals, or repeats, I am trying to work my body at the edge of its capabilities. As a result, there is little margin for error or unexpectedness. When things don't go as well as expected, the workout can feel something like slamming a car door on my head -- voluntarily, at 5:30 or 6:00 in the morning. I hate when that happens.

    Doing my 6x1200m workout this morning, I re-learned what all good experimental scientists know: too many free variables make it difficult to know why what happened happened when what happened isn't what you expected.

    What happened? I came up way short today. I was trying to run each repeat in 4:52 or less. The first was tough but right on mark. The second slowed down by 3 seconds and felt bad enough that I decided to jog lightly through the third. When I ran the fourth, I slowed down another 2 seconds and realized that I was going to be able to meet my goal for the day. In place of the fifth and sixth repeats, I chose to alternate faster laps with slower ones, in hopes of not turning the day into just another slow jog.

    But why did this happen? Here are some possibilities:

    • I tried to do too many repeats.
    • I tried to run each repeat too fast.
    • I ran too short a recovery period in between repeats.
    • I wasn't ready to run my repeats outdoors on the 400m track just yet.
    • My repeats were too long because I was not running the inside lane of the track.
    • I am still feeling lingering effects of my recent half marathon, two hard workouts last week too soon after the half, and a moderately fast 14-miler on Sunday?

    Running outside itself wasn't likely the problem, though the nature of the feedback is different. Attempting six repeats wasn't likely the problem, either, because the problem wasn't with Repeat 6; it was Repeat 3, or even #2.

    I think the most likely explanation is the combination of three variables. First, my legs are still tired from last week. Second, I tried running 400m recoveries instead of the more ordinary 600m (50% of the repeat distance). I will try to remedy those next week.

    Finally, and perhaps most important, I now realize that I was running repeats longer than 1200m. Last week's 4:53 repeats were right at my target distance, because I was running to lane markers on the indoor track. This morning, I was running three laps in Lane 4 of the 400m outdoor track. Four laps in Lane 4 is actually about 1.05 miles, so my three laps work out as a little over 1266m. That extra 66m is enormous when it comes to running at my limits. To do my target 1200m pace, I should have allowed myself an extra 16 seconds on each repeat!

    The idea that my laps were longer than planned didn't occur to me at all until I was out on the track, slogging through laps, asking myself, "But why?" I *hate* when that happens.

    I should have taken the feedback from my body at face value and adapted my pace. Whatever the reason, I was not going to be able to do 1:37 laps, so I should have eased off to a pace that I could sustain. Instead, I despaired a bit and gave up on a couple of the repeats. Note to self: Feedback is good; use it to get better.

    Multiply these three factors together, and you get a workout that does not go as planned.

    Then again, in retrospect, maybe my times weren't so bad after all. After crunching the numbers, I think that I can safely conclude that I was simply trying to run too fast.

    Unfortunately, things don't usually turn out so tidily. Ordinarily, I wouldn't know for certain the reason that the workout that did not go as planned, because I put too many variables into play. What I don't want to do is use my good fortune this week as rationalization for making the same mistake next week.

    My excuse, er, reason, for changing so many things at once is that training time is precious. From last Sunday, I had exactly 13 weeks until the Twin Cities Marathon. If I hope to meet my race goals, I need to make steady and rapid progress in my workouts.

    That is just the sort of reason that we software developers use to convince ourselves and our clients that we need to shove more and more features into the next release. It's the same excuse that teachers tell themselves and their students when they try to squeeze just one more topic into the already crowded syllabus of a course. The results are similar, too. The developers and instructors often fail to achieve their goals; software clients and students are left holding the bag. And then in the end, we are left asking ourselves why.

    Of course, this morning's experience also taught me another lesson: do my homework better when it comes to computing repeat distances on the track. "Do your homework" is, of course, also a fine piece of advice for software developers, software clients, teachers, and students alike. :-)


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

    July 06, 2005 12:53 PM

    What Do I Know About Teaching Programming?

    A week or so ago, I ran across Adam Connor's blog entry What do we know about teaching programming skills?. I wanted to respond immediately, either in a comment there or in a more complete essay here. But then I realized: I don't have anything succinct to say. As much as I think about teaching programming, and discuss it with friends, and write about facets of it here, I don't have a broadside that I can offer to folks like Adam who seek a concise, straightforward introduction to what we know about teaching programming. This realization disappointed me.

    For now, I can offer only a few points that seem to be recurring themes in how I understand how to teach programming. Later I will write up something that Adam and people in his position can use right away. Whether that will be in time to help Adam much, I don't know...

    In no particular order:

    • Concrete examples matter.

    • Practice, practice, practice!

    • Reading code helps us to write better code.

    • Expert programmers work top-down and bottom-up, but novices seem to learn best when working bottom-up first.

    • Students learn patterns of programs, whether or not you think about them or teach them explicitly. You are better suited to design your examples and instruction around the patterns you want them to learn, and then help them to name the patterns. A side benefit: you and your students will share a growing design vocabulary!

    • Read what you can by folks like Eliot Soloway and Robert Rist to learn about the educational psychology of programming.

    That's a start. You know what they say: start small, then grow.


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

    June 29, 2005 8:40 AM

    Learning from the Masters

    This spring I was asked to participate on a panel at XP2005, which recently wrapped up in the UK. This panel was on agile practices in education, and as you may guess I would have enjoyed sharing some of my ideas and learning from the other panelists and from the audience. Besides, I've not yet been to any of the agile software development conferences, and this seemed like a great opportunity. Unfortunately, work and family duties kept me home for what is turning out to be a mostly at-home summer.

    In lieu of attending XP2005, I've enjoyed reading blog reports of the goings-on. One of the highlights seems to have been Laurent Bossavit's Coding Dojo workshop. I can't say that I'm surprised. I've been reading Laurent's blog, Incipient(thoughts), for a while and exchanging occasional e-mail messages with him about software development, teaching, and learning. He has some neat ideas about learning how to develop software through communal practice and reflection, and he is putting those ideas into practice with his dojo.

    The Coding Dojo workshop inspired Uncle Bob to write about the notion of repeated practice of simple exercises. Practice has long been a theme of my blog, going back to one of my earliest posts. In particular, I have written several times about relatively small exercises that Joe Bergin and I call etudes, after the compositions that musicians practice for their own sake, to develop technical skills. The same idea shows up in an even more obviously physical metaphor in Pragmatic Dave's programming katas.

    The kata metaphor reminds us of the importance of repetition. As Dave wrote in another essay, students of the martial arts repeat basic sequences of moves for hours on end. After mastering these artificial sequences, the students move on to "kumite", or organized sparring under the supervision of a master. Kumite gives the student an opportunity to assemble sequences of basic moves into sequences that are meaningful in combat.

    Repeating programming etudes can offer a similar experience to the student programmer. My re-reading of Dave's article has me thinking about the value of creating programming etudes at two levels, one that exercises "basic moves" and one that gives the student an opportunity to assemble sequences of basic moves in the context of a more open-ended problem.

    But the pearl in my post-XP2005 reading hasn't been so much the katas or etudes themselves, but one of the ideas embedded in their practice: the act of emulating a master. The martial arts student imitates a master in the kata sequences; the piano student imitates a master in playing Chopin's etudes. The practice of emulating a master as a means to developing technical proficiency is ubiquitous in the art world. Renaissance painters learned their skills by emulating the masters to whom they were apprenticed. Writers often advise novices to imitate the voice or style of a writer they admire as a way to ingrain how to have a voice or follow a style. Rather than creating a mindless copycat, this practice allows the student to develop her own voice, to find or develop a style that suits their unique talents. Emulating the master constrains the student, which frees her to focus on the elements of the craft without the burden of speaking her own voice or being labeled as "derivative".

    Uncle Bob writes of how this idea means just as much in the abstract world of software design:

    Michael Feathers has long pondered the concept of "Design Sense". Good designers have a "sense" for design. They can convert a set of requirements into a design with little or not effort. It's as though their minds were wired to translate requirements to design. They can "feel" when a design is good or bad. They somehow intrinsically know which design alternatives to take at which point.

    Perhaps the best way to acquire "Design Sense" is to find someone who has it, put your fingers on top of theirs, put your eyeballs right behind theirs, and follow along as they design something. Learning a kata may be one way of accomplishing this.

    Watching someone solve a kata in a workshop can give you this sense. Participating in a workshop with a master, perhaps as programming partner, perhaps as supervisor, can, too.

    The idea isn't limited to software design. Emulating a master is a great way to learn a new programming language. About a month ago, someone on the domain-driven design mailing list asked about learning a new language:

    So assuming someone did want to want to learn to think differently what would you go with? Ruby, Python, Smalltalk?

    Ralph Johnson's answer echoed the importance of working with a master:

    I prefer Smalltalk. But it doesn't matter what I prefer. You should choose a language based on who is around you. Do you know somebody who is a fan of one of these languages? Could you talk regularly with this person? Better yet, could you do a project with this person?

    By far the best way to learn a language is to work with an expert in it. You should pick a language based on people who you know. One expert is all it takes, but you need one.

    The best situation is where you work regularly with the expert on a project using the language, even if it is only every Thursday night. It would be almost as good if you would work on the project on your own but bring code samples to the expert when you have lunch twice a week.

    It is possible to learn a language on your own, but it takes a long time to learn the spirit of a language unless you interact with experts.

    Smalltalk or Scheme may be the best in some objective (or entirely subjective!) sense, but unless you can work with an expert... it may not the right language for you, at least right now.

    As a student programmer -- and aren't we all? -- find a person to whom you can "apprentice" yourself. Work on projects with your "master", and emulate his style. Imitate not only high-level design style but also those little habits that seem idiosyncratic and unimportant: name your files and variables in the same way; start your programming sessions with the same rituals. You don't have to retain all of these habits forever, and you almost certainly won't. But in emulating the master you will learn and internalize patterns of practice, patterns of thinking, and, yes, patterns of design and programming. You'll internalize them through repetition in the context of real problems and real programs, which give the patterns the richness and connectedness that make them valuable.

    After lots of practice, you can begin to reflect on what you've learned and to create your own style and habits. In emulating a master first, though, you will have a chance to see deeper into the mind and actions of someone who understands and use what you see to begin to understand better yourself, without the pressure of needing to have a style on your own yet.

    If you are a computer scientist rather than a programmer, you can do much the same thing. Grad students have been doing this as long as there have been grad students. But in these days of the open-source software revolution, any programmer with a desire to learn has ample opportunity to go beyond the Powerbook on his desk. Join an open-source project and interact with a community of experts and learners -- and their code.

    And we still have open to us an a more traditional avenue, in even greater abundance, literature. Seek out a writer whose books and articles can serve in an expert's stead. Knuth, Floyd, Beck, Fowler... the list goes on and on. All can teach you through their prose and their code.

    Knowing and doing go hand in hand. Emulating the masters is an essential part of the path.


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

    June 23, 2005 6:28 PM

    Developing Empathy

    One thing I have noticed in my last few weeks preparing to move into the Big Office Downstairs: I view the actions of the administrators around me in a different light. Where I might have reacted immediately to some behavior, often negatively, I now am a bit more circumspect. What could make that seem the right thing to do? If nothing else, I am aware that I will soon be in the position of having to make such decisions, and it probably looks easier to do than it is. Kind of like playing Jeopardy! from the comfort of your own home... even Ken Jennings is an easy mark when you're sitting on your sofa.

    Swapping roles is a great way to develop empathy for others. This is certainly true for students and teachers. I do't know how many students who, after having to teach a short course at work or having to lecture in place of a traveling advisor, have told me, "I never knew how hard your job was!" Those students tend to treat their own instructors differently thereafter.

    Playing many different roles on a software team can serve a similar purpose. Developers who have tested or documented software often appreciate the difficulties of those jobs more than "pure" developers. Of course, playing different roles can help software people do more than develop empathy for their teammates; it can help them build skills that help them do all the jobs better. Writing and testing code come to my mind first in this regard.

    Empathy is a good trait to have. I hope to have more of it -- and put it to good use -- as a result of my new experience.


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

    June 21, 2005 8:59 AM

    Software for Writers

    Friday was my wife's and my 16th wedding anniversary. To celebrate, we went out for lunch prepared by a well-known local chef, put on at the Waterloo Center for the Arts. We had the pleasure of dining with Cedar Falls author Nancy Price, her daughter, and her son-in-law. Ms. Price is most famous for her novel Sleeping with the Enemy, which was made into a major motion picture starring Julia Roberts. Her father, Malcolm Price, was president of my university back in the 1940s.

    As is often the case, when these folks found out that I am a computer scientist, they eagerly shared their views on how programs help and hinder them in their jobs. All three have plenty of experience with computers, though as relatively non-technical users. The daughter and son-in-law hold Ph.D.s and write as a part of their jobs. The son-in-law, a botanist, claims to have been the first person in his department at Cal-Berkeley to produce his dissertation using a word processor.

    Ms. Price herself writes, and so her computer is a big part of her professional life. She wasn't shy in telling me that, in her experience, software still doesn't support her work very well. "Available programs just don't do a very good job helping an author work with a four- or five-hundred page document."

    The ensuing conversation led me to several questions.

    What programs do authors use these days? Microsoft Word is the de facto standard, I suppose, as it seems to be the de facto word-processing standard everywhere these days. As a faculty member, I have long tilted at windmills in an attempt to eliminate the Word .doc as the standard interchange format. I have heard from colleagues who've written books using Word, and they tell stories of annoying little quirks. But these days many publishers seem to be using Word, at least as the interface with their authors.

    I wasn't much help to my lunch partners in this regard, as I hang with a technical crowd that likes to get their hands dirty when writing. I wrote my dissertation using WordPerfect, and I did have to fight the system on issues such as pagination and figure placement. Some still use Framemaker, though that seems to be losing mindshare. The academic standard has long been LaTex, which has the author write at the lowest level in plain text. These days, software folks are as likely to roll their own authoring systems, writing with XML and creating custom solutions to their own problems, such as writing source code in text. But that isn't an option for most writers, who just want a program that lets them do what comes naturally.

    What should a novelist's workbench look like? What should it do? Googling on novelists software brings up lots and lots of tools, mostly for Windows. I don't have any good sense for what, if anything, these programs offer an author that a standard word processor doesn't have. When I examine my own writing needs, I usually end up thinking about technical problems such as source code in text that have no meaning to a poet or novelist. I guess I should find a project working with a writer to produce such a program -- that's always the best way for me to learn about the needs of a domain, by writing programs for the experts.

    Who would produce such a product? Ms. Price offered an answer, based only on an anecdote from a writing colleague. She said that he had spent some time working with a software company in an effort to find out why there weren't better programs for writers out there. He had reported back, she related with a playful smile, that the programs were only mediocre because there was no money to be made -- authors simply weren't a big enough or rich enough market to drive a software niche.

    This is the sort of cynical attitude that we software folks often encounter when we talk to users out in the world. I think it should bother us more than it sometimes does. Why are we willing, if not content, to let people think that we are unwilling or incapable of meeting the needs of users?

    Actually, a program for writers seems like the perfect sort of task for a small, specialty software house. My Google link earlier certainly indicates that a lot of small developers are in play. I doubt that the market could support an expensive program, but the right product might be able to attract enough volume to be lucrative enough. I don't imagine that this program would be a huge technical challenge to a software developer, which would leave plenty of energy for adapting the program and creating a wonderful interface.

    One last note from lunch. Our dining partners expressed great surprise that I, a computer scientist, am a Mac user. "I didn't figure they'd let you use a Mac in a CS department," the botanist said. I explained that I've been a Mac man since graduate school in the 1980s, though I've also been a Unix user for just as long. Now that Mac OS is a Unix, I explained, my tools are quite in vogue. "Even the Linux geeks will talk to me now!" If I'd had more time and an inclination to ramble on, I'd've told them how so many high profile folks in the software world use Macs these days. But they didn't seem to be sold on the virtues of a Mac, and lunch time was winding down.

    I enjoyed our lunch and conversation and was reminded that we computer scientists and software developers can find interesting questions almost everywhere we go, just by talking to users of the programs we write.


    Posted by Eugene Wallingford | Permalink | Categories: Software Development

    June 15, 2005 5:16 PM

    Pace and Expectations

    This isn't (just) a running post, though it starts with a running story.

    This morning, I did my last speed workout before the half marathon I will run in 11 days. I have not yet started back to real interval training since my marathon last October, Instead, I have been focusing on sustaining speed over longer distances. I would ordinarily have run 8 miles today at something just under 7:00/mile. With the half-marathon looming, I decided to test myself a bit and try to run 10 miles at 7:00/mile. In an ideal world, I would run that pace in my race. For my workout, I'd be slowing down a bit to target race pace but sustaining the pace for a longer stretch. It's good to train the body and mind to recognize and hold your target pace, so I was hoping to run all of my miles this morning in about the same time, between 6:50-6:54/mile.

    Going from 8 miles to 10 at a challenging pace may not seem like all that much, but it is a challenge. Usually, I finish my 8-mile workout pretty well spent, often having to work hard over the last three miles to keep the pace up. Where would I get the extra energy, both physical and mental, to go as fast for longer?

    In some ways, the physical part is the easier of the two. You can usually do more physically than you think. When a person tells me, "I can't even jog a block", I usually think they could. It might well hurt a bit, but they could do it. There muscles are more powerful than they realize. Since getting into better shape, I have often been surprised that my body could do more than I expected of it.

    The mental energy is another story. Even if my body can handle 10 miles at race pace, it will beginning feeling the stress much sooner. I knew that my body would be talking back to me this morning -- "Why? Why?" -- by the six or seventh mile. Being able to keep the faith and keep the pace becomes a mental challenge, answering the calls of fatigue and pain with energy found elsewhere.

    How did I manage? I think that the key was having a fixed and realistic target for the run. 10 miles isn't that much more than 8, so I know that my body can do it. Knowing that I only had to put together two more miles allowed my mind to adjust to the small increment before the run began. When I started to feel the workout in its seventh mile, my mind was ready... "Just a couple of more miles. Focus on the pace of individual laps. It's only two miles beyond what you usually do." Then, when I reached the 8-mile mark and my body mostly felt like stopping, I could say to myself, "Just a couple of more miles. You just did two tough ones. Will these really be any harder?" They weren't. My body could do it.

    I don't actually conduct this internal dialogue all that much as I run, only in the moments when my focus shifts away from the lap I'm running to the seemingly vast number of laps that remain. I can't run those laps yet; all I have is this one.

    I think it's a game of expectations. With reasonable expectations, the mind can help you do more than otherwise would be comfortable. An important part of reasonableness is duration--this only works well in the short term. Had I tried to run a full 13 miles this morning at race pace, my mind may have failed me. My body is still recovering from recent 5K and a 12-mile weekend run, and so it would begin to complain with increasing fervor as the miles added up. And I doubt that my spirit would have been strong enough to win the battle, because doing a 13 miles at race pace isn't reasonable for this day. But with a reasonable short-term expectation, I was able to handle crunch time with that short-term horizon in mind.

    I've written about sustainable pace before, including about what happens when I try to go faster than a sustainable pace for too long and how software developers might train for speed. (I've even referenced sustainable pace in the context of a Bill Murray film.) But the idea has been on mind again lately in a different way. The pace that is sustainable is closely tied to one's expectations about its endurance. This mental expectations game applies in running, but it also applies in other human endeavors, including software development.

    A recent thread on the XP mailing list considered the proposition that "crunch mode" doesn't work. There didn't seem to be many folks defending the side that crunch mode can work. That's because most people were thinking about sustainable pace over the long run, which is what agile folks tend to mean when they talk about pace. They do so for good reason, because the danger in software development has usually been for companies to try to overdo it, to push developers too far and too fast, with the result being a decrease in software quality and ultimately the burn-out of the developers.

    At least one person, though, argued that crunch mode can work. The gist of SirGilligan's claim is that a software team can go faster and still do quality work -- but only for a well-defined short term. He even used a running metaphor in defining such a crunch time: We are not 1/3 along the way, we are in the straight-a-way and heading for the finish line. How can developers win the expectations game in such a scenario? The end is clearly in sight:

    Pending features are well defined. Order of feature implementation is defined. Team is excited for the chance to deliver. It is the team's choice and idea to crunch, not some manager's idea. We enter crunch mode! After we deliver everyone gets the following Friday and Monday off for a four-day weekend!

    That sounds an awful lot like what a runner does when she races a marathon or half-marathon faster than she thinks otherwise possible. The pending goal is well-defined. The runner is excited to deliver. She chooses to push faster. And, after the race, you take a few days off for rest. A party, of course, is always in order!

    I think the great ones are able to manage their expectations in a way that allows them to do more than usual for a short while. The good news for the rest of us is that we can learn to do the same, which gives us the ability to succeed in a wider variety of circumstances. Just always keep in mind: You can't keep going faster indefinitely.


    Posted by Eugene Wallingford | Permalink | Categories: Running, Software Development

    June 12, 2005 5:06 PM

    On Making Things Up

    As I think I've mentioned here before, I am a big fan of Electron Blue, a blog written by a professional artist who has taken up the study of physics in middle age. Her essays offer insights into the mind of an artist as it comes into contact with the abstractions of physics and math. Sometimes, the two mindsets are quite different, and others they are surprisingly in tune.

    I just loved this line, taken from an essay on some of the similarities between a creator's mind and a theoretical scientists:

    When I read stuff about dark energy and string theory and other theoretical explorations, I sometimes have to laugh, and then I say, "And you scientists think that we artists make things up!"

    Anyone who has done graduate research in the sciences knows how much of theory making is really story telling. We in computer science, despite working with ethereal computation as our reality, are perhaps not quite so make-believe as our friends in physics, whose efforts to explain the workings of the physical world long ago escaped the range of our senses.

    Then again, I'm sure some people look at XP and think, "It's better to program in pairs? It's better to write code with duplication and then 'refactor'? Ri-i-i-i-ght." What a story!


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

    June 10, 2005 3:10 PM

    Another Advertisement for Smalltalk

    Last week, I posted a note on a cool consequence of Smalltalk being written in Smalltalk, the ability to change the compiler to handle new kinds of numeric literals. Here is another neat little feature of Smalltalk: You can quit the interpreter in the middle of executing code, and when you start back up the interpreter will finish executing the code!

    Consider this snippet of code:

    Smalltalk snapshot: true andQuit: true.
    ... code to execute at next start-up, such as:
    PWS serveOnPort: 80 loggingTo: 'log.txt'

    If you execute this piece of code, whether as a method body or as stand-alone code in a workspace, it will execute the first statement -- which saves the image and quits. But in saving the image, you save the state of the execution, which is precisely this point in the code being executed. When you next start up the system, it will resume write where it left off, in this case with the message to start up a web server.

    How I wish my Java environments did this...

    This is another one of those things that you want Java, Perl, Python, and Ruby programmers to know about Smalltalk: it isn't just a language; it is a living system of objects. When you program in Smalltalk, you don't think of building a new program from scratch; you think of molding and growing the initial system to meet your needs.

    This example is from Squeak, the open-source Smalltalk I use when I have the chance to use Smalltalk. I ran across the idea at Blaine Buxton's blog, and he found the idea in a Squeak Swiki entry for running a Squeak image headless. (A "headless image" is one that doesn't come up interactively with a user. That is especially useful for running the system in the background to drive some application, say a web server.)


    Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

    June 07, 2005 1:44 PM

    Turning Students onto Entrepreneurship

    Modern invention has been a great leveler.
    A machine may operate far more quickly
    than a political or economic measure to
    abolish privilege and wipe out the distinctions
    of class or finance.

    -- Ivor Brown, The Heart of England

    I finally read Paul Graham's newest essay, Hiring is Obsolete, this weekend. I've been thinking about the place of entrepreneurship in my students' plans recently myself. When I gave my interview presentation to our faculty when applying to be department head, I talked about how -- contrary to enrollment trends and popular perception -- this is the best time ever to go into computer science. One of the biggest reasons is the opportunity for ambitious students to start their own companies.

    Philip Greenspun related an illustrative story in his blog:

    The engineering staff at Google threw a big party for Silicon Valley nerds last Thursday night [May 5], ...

    Larry Page, one of the founders, gave an inspiring talk about what a great time this is to be an engineer. He recalled how at one point Google had five employees and two million customers. Outside of Internet applications it is tough to imagine where that would be possible. Page also talked about the enjoyment of launching something, getting feedback from users, and refining the service on the fly. ...

    This sounds like the same sort of experience that Graham touts from ViaWeb.

    Admittedly, not every start-up will be a ViaWeb or a Google, but that's not the point. The ecosphere is rife with opportunities for small companies to fill niches not currently being served by larger companies. Not all such companies are doing work specifically for the web, but the web makes it possible for them to make their products visible and available. The web reduces a company's need for some of the traditional trappings of a business, such as a large, dedicated sales staff.

    The sort of entrepreneurship Graham touts is more common in Silicon Valley and the Route 128 corridor, and more generally in large metropolitan areas, but Grahams's advice applies even here in the Great Midwest -- no, not "even here", but especially here. The whole point of the web's effect on business is that almost anyone almost anywhere can now create a business that does something no one else is doing, or does something others are doing but better, make a lot of money. Ideas and hard work are now more important than location or who you know.

    UNI students have had a few successes in this regard. I keep in close touch with one successful entrepreneur who is former student of ours. When he was a student here, he already exhibited the ambition that would lead to his business success. He read broadly on the web and software and technology. He asked questions all the time. By the time he left UNI, he had already started a web hosting company with a vision to do things differently and better. I love to visit his place company, give whatever advice I can still give, and learn from him and what he is doing.

    Back in the old days, most people would have moved to New York or San Francisco in order to start his first company -- because that's "where the action was". I'm sure that some people told him that he should move to Chicago or at least Minneapolis to have a chance to succeed. But he started his company right here in little ol' Cedar Falls, Iowa, and did just fine. He can enjoy the life available in a small city in a relatively rural part of America. His company's building is ten feet from a paved bike trail that circles a small lake and connects into a system of miles and miles of trails. His margins can be lower because his costs of doing business are lower. And working with the growing tech community here he can dream as big as he likes and is willing to work.

    This guy hasn't made it big like Graham or Page or Gates, but he is one example of the bountiful opportunities available to students studying at schools like UNI throughout the world. And he could never have learned as much or done as much if he had followed the steady flow of our students to the big-box insurance companies and service businesses that hire most of our students.

    How can we -- instructors and the world at large -- help students appreciate that the "cage is open", as Graham describes the Brave New World of business? The tendency of most university professors is to offer another course :-). When I was a grad student at Michigan State, I sat in on a course during my last quarter that was being offered jointly by the Colleges of Engineering and Business to teach some essential skills of the entrepreneurial engineer. I wish that it had come earlier in my studies because by then my mind was set on either going corporate (AI research with a big company like Ford or Price Waterhouse) or going academic.

    There is certainly some value in incorporating this kind of material into our curricula and maybe even offering stand-alone courses with an entrepreneurial bent. But this transition in how the world works is more about attitude and awareness than the classroom. Students have to think of starting a company in the same they think of going to work for IBM or going to grad school, as a natural option open to everyone. Universities will serve students better by making starting their own companies a standard part of how we talk about their futures and of the futures we expose them to.

    There are some particular skills that universities need to help students develop, beyond what we teach now. First and foremost is the ability to identify problems with economic potential. We are pretty good at helping students learn to identify cool problems with academic potential, because that's what we do when we do our own research. But a problem of basic academic interest rarely results in a program or service that someone would pay for, at least not enough someones to make it reasonable as the basis for a commercial venture. Graham gives some advice in his various essays on this topic, and the key almost always comes down to "Know users." Only by observing carefully people who are doing real work are we likely to stumble upon those inefficiencies that they would be willing to pay to make go away. Eric Sink has also written some articles useful to folks who are thinking about starting their own software house.

    The other things we teach students are still important, too. A start-up company needs programmers, people who know how to develop software well and who have strong analytic skills. "The basics" such as data structures, algorithms, and programming languages are still the basics. Students just need to have a mindset in which they look for ways to use these skills to solve real problems that real users have -- problems that no one else is solving for them yet.

    Hiring is Obsolete has more to say than just that students should consider being entrepreneurs. In particular, Graham talks about the opportunities available to large companies in an ecosphere in which start-ups do initial R&D and identify the most capable software developers. But I think that these big companies will take care of themselves. My interest is more in what we can do better in the university, including what we can do to get folks to see what a wonderful time this is to study computer science.

    I think I should take my next sabbatical working for one of my former students...


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

    June 06, 2005 5:04 PM

    A Personal Goodbye to AAAI

    the AAAI logo

    I recently made a bittersweet decision: I am not going to renew my membership in AAAI. The AAAI is the American Association for Artificial Intelligence, and I have been a member since 1987, when I joined as a graduate student.

    Like many computer scientists who grew up in the '70s and '80s, AI was the siren that lured me to computing. Programs that could play chess, speak and understand English sentences, create a piece of music; programs that could learn from experience... so many tantalizing ideas that all lay in the sphere of AI. I wanted to understand how the mind works, and how I could make one, if only a pretend one in the silicon of the rather inelegant machines of the day.

    I remember when I first discovered Gödel, Escher, Bach and was enchanted even further by the idea of self-reference, by the intertwining worlds of music, art, mathematics, and computers that bespoke a truth much deeper than I had ever understood before. The book took me a whole summer to read, because every few pages set my mind whirling with possibilities that I had to think through before moving on.

    I did my doctoral work in AI, at the intersection of knowledge-based systems and memory-based systems, and reveled in my years as a graduate student, during which the Turing Test and Herb Simon's sciences of the artificial and cognitive science were constant topics of discussion and debate. These ideas and their implications for the world mattered so much to us. Even more, AI led me to study psychology and philosophy, where I encountered worlds of new and challenging ideas that made me a better and more well-rounded thinker.

    My AI research continued in my early years as an assistant professor, but soon my interests and the needs of my institution pulled me in other directions. These days, I think more about programming support tools and programming languages than I do AI. I still love the AI Enterprise but find myself on the outside looking in more often than not. I still love the idea of machine learning, but the details of modern machine learning research no longer enthrall me. Maybe the field matured, or I changed. The AI that most interests me now is whatever technique I need to build a better tool to support programmers in their task. Still, a good game-playing program still draws my attention, at least for a little while...

    In any case, the idea of paying $95 a year to receive another set of printed magazines that I don't have time to study in depth seems wasteful of paper and money both. I read some AI stuff on the web when I need or want, and I keep up with what my students are doing with AI. But I have to admit that I'm not an AI scientist anymore.

    For some reason, that is easier to be than to say.


    Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

    June 03, 2005 2:34 PM

    Changed Your Language Today?

    I have had this link and quote in my "to blog" folder for a long time:

    ... the one thing that a Ruby (or Python) programmer should know about Smalltalk is, it's all written in Smalltalk.

    But I wanted to have a good reason to write about it. Why does it matter to a Smalltalker that his language and environment are implemented in Smalltalk itself?

    Today, I ran across a dynamite example that brings the point home. David Buck

    ... was working for a company once that did a lot of work with large numbers. It's hard, though, to write 45 billion as 45000000000. It's very hard to read. Let's change the compiler to accept the syntax 45b as 45 billion.

    Sisyphus pushing a stone up a mountain

    And he did it -- by adding six lines of code to his standard working environment and saving the changes. This is the sort of openness that makes working in Java or most any other ordinary language feel like pushing rocks up a mountain.

    Lisp and Scheme read macros give you a similar sort of power, and you can use regular macros to create many kinds of new syntax. But for me, Smalltalk stands above the crowd in its pliability. If you want to make the language you want to use, start with Smalltalk as your raw material.


    Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

    June 03, 2005 1:57 PM

    Reaping What You Sow

    I ran into this quote over at Ben Hyde's blog:

    Customers have a tendency to become like the kind of customers you treat them.

    Ben related the quote as a commentary on trust in commerce. (Trust and social relationships are ongoing themes of his blog.) He notes that he has observed this truth in many situations. I have, too. Indeed, I think this truth applies in almost all human relationships.

    (Like all generalizations, this one isn't foolproof, so feel free to prefix each of the following claims with "by and large" or your favorite waffle words.)

    Parents and Children

    Children grow into the people you expect them to be. The best sort of discipline for most children is to create an environment in which children know what your expectations are, and then live consistently in that way. Nagging youngsters doesn't work; they come to expect you to nag before they know you care about something. Yelling and screaming don't work, either; they come to think that you don't believe they can behave without being verbally assaulted. If you simply set a standard and then live as if you expect them to meet the standard, they will. When they don't, don't resort to needy negative reinforcement. Usually they know they've fallen short and strive to do better the next time.

    Teachers and Students

    Students become what their teachers expect of them, too. If you act as if they are not trustworthy, say, by creating elaborate rules for late work, cheating, and grading, they will soon look for ways to game the system. If you act as if they don't respect class time, say, by wasting it yourself through lack of preparation or rambling digression, they will soon come not to value their time in class.

    If you set a high standard and expect them to learn and achieve, they usually will. If you trust them with masterpieces, they will come to value masterpieces.

    Developers and Users

    The quote applies to all sorts of developer/user relationships. If software developers don't trust their clients, then their clients will start to look out for themselves at the developer's expense. If an API designer acts as if programmers are not smart or reasonable enough to use the API wisely, and so creates elaborate rituals to be followed to ensure that programmers are doing the right thing, then programmers will look for ways to game the API. The result is hacks that confirm the API designer's expectations.

    Agile methods place a high premium on developing a mutually beneficial relationship between the client and the programmer. The result is that programmers and clients feel free to be what they should be to one another: partners in creating something valuable.

    Managers and Team Members

    This truth is a good thing to keep in mind for someone embarking on an administrative or managerial position. When "bosses" treat their "employees" as adversaries in a competition, the employees soon become adversaries. They do so almost out of necessity, given the power imbalance that exists between the parties. But if a manager approaches the rest of the team with openness, transparency, and respect, I think that most members of the team will also respond in kind.

    Husbands and Wives

    All of the relationships considered above are hierarchical or otherwise imbalanced. What about peer relationships? I think the assertion still holds. In my many years of marriage, I've noticed that my wife and I often come to behave in the way we think our spouse expects. When one of us acts as if the other is untrustworthy, the other comes to protect his or her own interest. When one of us acts as if the other is incapable of contributing to a particular part of our lives together, the other stops caring to contribute. But when we act as if we are both intelligent, trustworthy, caring, and respectful, we receive that back from each other.

    ----

    Given its wide range of applicability, I think that the truism needs to be restated more generally. Perhaps:

    People tend to become like the kind of people you treat them to be.

    Or maybe we can restate it as a new sort of Golden Rule:

    Treat people like the kind of people you want -- or expect -- them to be.

    Or perhaps "Do unto others as you expect them to be."


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

    June 02, 2005 6:51 PM

    Who Says Open Source Doesn't Pay?

    Google's Summer of Code flyer

    Leave it to the guys from Google to offer the Summer of Code program for students. Complete an open-source project through one of Google's collaborators, and Google will give you a $4500 award. The collaborators range from relatively large groups such as Apache and FreeBSD, through medium-sized projects such as Subversion and Mono, down to specific software tools such as Jabber and Blender. Of course, the Perl Foundation, the Python Software Foundation, and Google itself are supporting projects. You can even work on open-source projects in Lisp for LispNYC, a Lisp advocacy group!

    The program bears a strong resemblance to the Paul Graham-led Summer Founders Program. But the Summer of Code is much less ambitious -- you don't need to launch a tech start-up; you only have to hack some code -- and so is likely to have a broader and more immediate effect on the tech world. Of course, if one of the SFP start-ups take off like Google or even ViaWeb, then the effects of the SFP could be much deeper and longer lasting.

    This is another slick move from the Google image machine. A bunch of $4500 awards are pocket change to Google, and in exchange they generate great PR and establish hefty goodwill with the open-source organizations participating.

    From my perspective, the best part of the Summer of Code is stated right on its web page: "This Summer, don't let your programming skills lie fallow...". I give this advice to students all the time, though they don't often appreciate its importance until the fall semester starts and they feel the rust in their programming joints. "Use it, or lose it" is trite but true, especially for nascent skills that are not yet fully developed or internalized. Practice, practice, practice.

    The Summer of Code is a great chance for ambitious and relatively advance students to use this summer for their own good, by digging deep into a real project and becoming better programmers. If you feel up to it, give it a try. But even if you don't, find some project to work on, even if it's just one for your amusement. Perhaps I should say especially if it's just one for your amusement -- most of the great software in this world was originally written by people who wanted the end result for themselves. Choose a project that will stretch your skills a bit; that will force you to improve in the process. Don't worry about getting stuck... This isn't for class credit, so you can take the time you need to solve problems. And, if you really get stuck, you can always e-mail your favorite professor with a question. :-)

    Oh, if you do want to take Google up on its offer, you will want to hurry. Applications are due on June 14.


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

    June 02, 2005 1:46 PM

    On "Devoid of Content"

    A couple of days ago, blog reader Mike McMillan sent me a link to Stanley Fish's New York Times op-ed piece, Devoid of Content. Since then, several of my CS colleagues have recommended this article. Why all the interest in an opinion piece written by an English professor?

    The composition courses that most university students take these days emphasize writing about something: current events, everyday life, or literature. But Fish's freshman composition class does something much different. He asks students to create a new language, "complete with a syntax, a lexicon, a text, rules for translating the text and strategies for teaching your language to fellow students". He argues that the best way to learn how to write is to have a deep understanding of "a single proposition: A sentence is a structure of logical relationships." His students achieve this understanding by having to design the mechanisms by which sentences represent relationships, such as tense, number, manner, mood, and agency.

    Fish stakes out a position that is out of step with contemporary academia: Learning to write is about form, not content. Content is not only the not the point; it is a dangerous delusion that prevents students from learning what they most need.

    Content is a lure and a delusion, and it should be banished from the classroom. Form is the way.

    Fish doesn't say that content isn't important, only that it's should not be the focus of learning to write. Students learn content in their science courses, their social science courses, and their humanities courses -- yes, even in their literature courses.

    (I, for one, am pleased to see Fish distinguish the goals of the composition courses taught in English departments from the goals of the literature courses taught there. Too many students lose interest in their comp courses when they are forced to write about, oh, a poem by Edna St. Vincent Millay. Just because a student doesn't connect with twentieth-century lyric poetry doesn't mean that he shouldn't or can't learn to write well.)

    So, how is Fish's argument relevant to a technical audience? If you have read my blog much, you can probably see my interest in the article. I like to read books about writing, to explore ways of writing better programs. I've also written a little about the role form plays in evaluating technical papers and unleashing creativity. On the other side of the issue, though, I have several times recently about the role of real problems and compelling examples in learning to program. My time at ChiliPLoP 2005 was spent working with friends to explore some compelling examples for CS1.

    In the context of this ongoing discussion among CS educators, one of my friends sloganized Fish's position as "It's not the application, stupid; it's the BNF."

    So, could I teach my freshman computer programming class after Fish's style? Probably not by mimicking his approach note for note, but perhaps by adopting the spirit of his approach.

    We first must recognize that freshman CS students are usually in a different intellectual state from freshman comp students. When students reach the university, they may not have studied tense and mood and number in much detail, but they do have an implicit understanding of language on which the instructor can draw. Students at my university already know English in a couple of ways. First, they speak the language well enough to participate in everyday oral discourse. Second, they know enough at least to string together words in a written form, though perhaps not well enough to please Fish or me.

    My first-year programming students usually know little or nothing about a programming language, either as a tool for simple communication or in terms of its underlying syntactic structures. When Fish's students walk into his classroom, he can immediately start a conversation with them, in a rich language they share. He can offer endless example sentences for his students to dissect, to rearrange, to understand in a new way. These sentences may be context-free, but they are sentences.

    In a first-year programming course, instructors typically have to spiral our dissection of programs with the learning of new language features and syntax. The more complex the language, the wider and longer the spiral must be.

    Using a simple computer language might make an approach like Fish's work in a CS1 course. I think of the How to Design Programs project in these terms. Scheme is simple enough syntactically that the authors can rather quickly focus on the structure of programs, much as Fish focuses on the structure of sentences. The HtDP approach emphasizes form through its use of BNF definitions and "design recipes". However, I don't get the sense that HtDP removes content from the classroom so much as it removes it from the center of attention. Felleisen et al. still try to engage their students with examples that might interest someone.

    So, I think that we may well be able to teach introductory programming in the spirit of Fish's approach. But is it a good idea? How much of the motivation to learn how to program springs from the desire to do something particular? I do not know the answer to this question, but it lies at the center of the real problems/compelling examples discussion.

    In an unexpected twist of fate, I was thumbing through Mark Guzdial's new book, Introduction to Computing and Programming with Python: A Multimedia Approach, and read the opening sentences of its preface:

    Research on computing education clearly demonstrates that one doesn't just "learn to program." One learns to program something [5,20], and the motivation to do that something can make the difference between learning and not learning to program [7].

    (The references are to papers on situated learning of the sort Seymour Papert has long advocated.)

    I certainly find myself in the compelling problems camp these days and so am heartened by Guzdial's quote, and the idea embodied in his text. But I also feel a strong pull to find ways to emphasize the forms that will help students become solid programmers. That pull is the essence of my interest in documenting elementary programming patterns and using them to gain leverage in the classroom.

    Regardless of how directly we might use Fish's approach to teach first-year courses in programming, I am intrigued by what seems to me to be a much cleaner connection between his ideas and the CS curriculum, the traditional Programming Languages course! I'll be teaching our junior/senior level course in languages this fall, and it seems that I could adopt Fish's course outline almost intact. I could walk in on Day 1 and announce that, by the end of the semester, each group of students will have created a new programming language, complete with a syntax, a set of primitive expressions, rules for translating programs, and the whole bit. Their evolving language designs would serve as the impetus for exploring the elements of language at a deeper level, touching all the traditional topics such as bindings, types, scope, control structures, subprograms, and so on. We could even implement our growing understanding in a series of increasingly complex interpreters that extract behavior from syntactic expressions.

    Actually, this isn't too far from the approach that I have used in the past, based on the textbook Essentials of Programming Languages. I'll need to teach the students some functional programming in Scheme first, but I could then turn students loose to design and implement their own languages. I could still use the EOPL-based language that I call Babel as my demonstration language in class.

    School's barely out for the summer, and I'm already jazzed by a new idea for my fall class. I hope I don't peak too soon. :-)

    As you can see, there are lots of reasons that Fish's op-ed piece has attracted the attention of CS folks. It's about language and learning to use it, which is ultimately what much of computer science and software development are about.

    Have you heard of Stanley Fish before? I first ran into him and his work when I read a blog entry by Brian Marick on the role the reader plays in how we write code and comments. Brian cited Fish's work on reader-response criticism and hypothesized an application of it to programming. You may have encountered Fish through Brian's article, too, if you've read one of my oldest blog entries. I finally checked the book by Fish that Brian recommended so long ago out of the library today -- along with another Fish book, The Trouble with Principle, which pads my league-leading millions total. (This book is just for kicks.)


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

    May 31, 2005 5:50 PM

    Agile Moments from Primitive Obsessions

    [ See what happens when I start talking? I can't shut up. :-) ]

    My previous entry brought to mind two related ideas. Think of these as more Agile Moments.

    The Delgado Codex

    I ran across a neat little example of reflective practice on the major league baseball diamond in The Scholarly Rigor of Carlos Delgado. Carlos is the first baseman for the Florida Marlins in U.S. baseball's National League. He apparently has the agile habit of recording detailed information about every one of his at-bats in a notebook he keeps with him in the dugout. By collecting this data, he is able to derive feedback from his results and use that to improve his future at-bats.

    As the article points out, most professional sports teams -- at least in America -- record all of their performances these days and then mine the film for information they can use to do better next time out. Delgado, "like a medieval Benedictine at Monte Cassino", is one of the few major leaguers who still use the ancient technologies of pencil and paper to personally track his own performances. The act of writing is valuable on its own, but I think that as important is the fact that Delgado reflects on his performance immediately after the event, when the physical sensations of the performance are still fresh and accessible to his conscious mind.

    How is this related to my previous post? I think that we programmers can benefit from such a habit. If we recorded the smells that underlay our refactorings for a month or even a week, we would all probably have a much better sense of our own tendencies as programmers, which we could then feed back into our next code. And, if we shared our experiences, we might develop an even more comprehensive catalog of smells and refactorings as a community. If it's good enough for Donald Knuth, it ought to work for me, too.

    Agility works for Delgado, one of the better offensive players in all of baseball. Knowing about his habit, I'm even happier to have him as a member of my rotisserie baseball team, the Ice Nine. :-)

    Intentional Duplication

    The Zen Refactoring thread on the XP mailing list eventually came around to the idea deliberately creating code duplication. The idea is this: It is easier first to write code that duplicates other code and then to factor the duplication out later than it is to write clean code first or to refactor first and then add the new code.

    I operate in this way most of the time. It allows me to add a new feature to my code immediately, with as little work as possible, without speculating about duplication that might occur in the future. Once I see the actual duplication, I make it go away. Copy-and-paste can be my friend.

    This technique is one way that you can refactor your code toward suitable domain abstractions away from primitive data. When you run into a situation where you find yourself handling a tolerance in multiple places, Extract Class does the trick. This isn't a foolproof approach, though, as Chris Wheeler pointed out in his article. What happens when you have references to mass-as-an-int in zillions of places and only then does the client say, "Um, we allow tolerances of 0.1g"? Good design and good refactoring tools are your friend then.

    In the same thread, Ron Jeffries commented:

    > I have also sometimes created the duplication, and then
    > worked to make the duplicated code as similar as possible
    > before removing the duplication. Does anyone else do this?

    I once saw Kent Beck do that in a most amazing way, but I haven't learned the trick of making code look similar prior to removing duplication; would love to see an example.

    Now I have fodder for a new blog entry: to write up a simple example of this technique that I use in my freshman-level OOP programming course. It's a wonderful example of how a little refactoring can make a nice design fall out naturally.

    How is this related to my previous post? Duplication is one of my pet code smells, though I often create it willingly, with the intention of immediately factoring it out. Like Primitive Obsession, though you have to learn to strike a proper balance between too little and too much. Just right is hard to find sometimes.


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

    May 31, 2005 4:58 PM

    Primitive Obsession and Balance

    Recently, Chris Wheeler posted a thoughtful blog entry called My Favourite Smells, which described only one smell, but one every OOP programmer knows deep in his soul: using a primitive data type instead of a domain-specific type. James Shore calls this smell Primitive Obsession, and Kevin Rutherford calls it Primitive Feature Envy.

    Chris has been justifiably lauded for starting a conversation on this topic. I find this smell in my programs and even in many of the programs I read from good OOP programmers. When programmers are first learning to write object-oriented programs, the tendency to write code in terms only of the primitive data types is hard to shake. Who needs that Piece class, when a simple integer flag taking values from 1 to 4 will do just fine? (Heck, we can always use Hungarian Notation to make the semantics clear. :-) When students come to see the value of that Piece class, they begin to see the value of OOP.

    That said, we have to be careful to remember that this smell is not an absolute indicator. There is an inherent tension between the desire to create classes to model the domain more closely and the desire to do the simplest thing that could possibly work. If I try to wrap every piece of primitive data in its own class, I can very quickly create a lot of unnecessary code that makes my program worse, not better. My program looks like it has levels of abstraction that simply aren't there.

    That's not the sort of thing that Chris, James, and Kevin are advocating, of course. But we need to learn how to strike the proper balance between Primitive Obsession and Class Obsession, to find the abstractions that make up our domain and implement them as such. I think that this is one of the reasons that Eric Evans' book Domain-Driven Design is so important: it goes a long way toward teaching us how to make these choices. Ultimately, though, you can only grok this idea through experience, which usually means doing it wrong many times in both directions so that your mind learns the patterns of good designs. As Chris', James', and Kevin's articles all point out, most of us start with a predilection to err on the side of primitives.

    One way to push yourself to learn this balance is to use the Three Bears pattern first described by Kent Beck to create situations in which you confront the consequences of going too far one way or the other. I think that this can be another one of those programming etudes that help you become a better programmer, a lá the Polymorphism Challenge that Joe Bergin and I used at SIGCSE 2005, in which we had folks rewrite some standard programs using few or zero if statements.

    In order to feel the kind of effects that Chris describes in his article, you have to live with your code for a while, until the specification changes and you need that tolerance around your masses. I think that the folks running the ICFP 2005 programming contest are using a wonderful mechanism to gauge a program's ability to respond to change. They plan to collect the contestants' submissions and then, a couple of weeks later, introduce a change in the spec and require the contestants to adapt their programs on an even shorter deadline. What a wonderful idea! This might be a nice way to help students learn the value of adaptable code. Certainly, Primitive Obsession is not much of a problem if you never encounter the need for an abstraction.

    Ron Jeffries posted a message to the XP discussion list earlier today confessing that one of his weaknesses as a programmer is a tendency to create small classes too quickly. As an old Smalltalker, he may be on the opposite end of the continuum from most folks. But we need a good name for the smell that permeates his code, too. My "Class Obsession" from above is rather pedestrian. Do you have better name? Please share... Whatever the name, I suspect that Ron's recognition of his tendency makes it easier for him to combat. At least he knows to pay attention.

    Chris's article starts with the idea of favorite smells but then settles on one. It occurs to me that I should tell you my personal favorite smell. I suspect that it relates to duplication; my students certainly hear that mantra from me all the time. I will have to think a bit...


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

    May 25, 2005 1:37 PM

    Waiting

    Vaclav Havel

    Last weekend, while my daughter was doing a final practice for her Suzuki Book I recital, I picked Vaclav Havel's The Art of the Impossible: Politics as Morality in Practice off the piano teacher's bookshelf for a little reading. This is a collection of speeches and short essays that Havel in the first half of the 1990s about his role as dissident, reformer, and president of the Czech Republic. He is, of course, famous as a poet, and his writing and speaking style have a poet's flare.

    I ended up spending most of my time with Havel's speech to the Academy of Humanities and Political Sciences in Paris on October 27, 1992. (I just noticed the date -- that's my birthday!) This speech discussed the different forms of waiting.

    Vladimir and Estragon in Waiting for Godot

    The first kind is sometimes characterized as waiting for Godot, after the absurdist play by Samuel Beckett. In this form, people wait for some sort of universal salvation. They have no real hope that life will get better, so they hold tightly to an irrational illusion of hope. Havel says that, for much of the 20th century, residents of the former communist world waited for Godot.

    At the opposite end of the waiting spectrum lies patience. Havel describes patience as waiting out of principle -- doing the right thing because it is right, not out of any expectation of immediate satisfaction. In this sense, patience is "waiting as a state of hope, not as an expression of hopelessness". Havel believes that the dissidents who ultimately toppled the communist regimes behind the Iron Curtain practiced this sort of waiting.

    When the curtain fell and the people of, say, Czechoslovakia took their first unsteady steps into the light of the western world, folks practicing the different forms of waiting encountered distinctive problems. Those who had been waiting for Godot felt adrift in a complex world unlike anything they had known or expected. They had to learn how to hope and to be free again.

    You might think that the patient dissidents would have adjusted better, but they faced an unexpected problem. They had hoped for and imagined a free world around them, but when they became free things didn't change fast enough. Havel relates his own struggles at being too idealistic and now impatient with the rate at which the Czech and Slovak republics assumed the mantel of democratic responsibility. Like many revolutionaries, he was criticized as out of his element in the new world, that he was most effective in the role of dissident but ineffective in the role of democratic leader.

    What struck me most about this essay came next. Havel recognized the problem: He had waited patiently as a dissident because he had no control over how anyone but himself behaved. Now that the huge impediment of an authoritarian regime had been surmounted, he found that he had become impatient for all the details of a democratic system to fall into place. He no longer waited well.

    In short, I thought time belonged to me. ...

    The world, Being, and history have their own time. We can, of course, enter that time in a creative way, but none of us has it entirely in his hands. The world and Being do heed the commands of the technologist or the technocrat....

    In his own transition from dissident to democratic leader, Havel learned again that he had to wait patiently as the world takes its "own meandering course". He asserts that the "postmodern politician" must learn waiting as patience -- a waiting founded on a deep respect for the world and its sense of time. Read:

    His actions cannot derive from impersonal analysis; they must come out of a personal point of view, which cannot be based on a sense of superiority but must spring from humility.

    When the world changed, even in the way for which he had been working, Havel had to learn again how to be patient.

    I think that the art of waiting is something that has to be learned. We must patiently plant the seeds and water the ground well, and give the plants exactly the amount of time they need to mature.

    Just as we cannot fool a plant, we cannot fool history.

    I think that 'waiting patiently as the world takes its own meandering course' translates into showing respect for people and the rate at which they can assimilate new ideas and change their behavior.

    Perhaps this speech affected me as it did because I am now thinking about leading my department. I certainly do not face a situation quite as extreme as Havel did when the communist regime fell in Czechoslovakia, yet I am in a situation where people do not trust the future as much as I'd like, and I need to find a way to help my department move in that direction. As Havel reminds me, I cannot move the department myself; I can only patiently plant the seeds of trust, water the ground well, and give the plants the time they need to grow.

    The value of this sort of waiting is not limited to the world of administration. Good instructors need to wait patiently, working with students to create the atmosphere in which they can grow and then giving them time and opportunity to do so.

    I also think that this sort of waiting holds great value in the world of software development. Agile methods are often characterized by folks in the traditional software engineering world as impatient in their desire to get to code sooner. But I think the opposite is true -- the agile methods are all about patience: waiting to write a piece of code until you really know what it should do, and waiting to design the whole program until you understand the world well enough to do it right. In this sense, traditional software engineering is the impatient approach, telling us to presumptuously design grand solutions to force the world to follow our senses of direction and time. The worlds in which most programs live are too complex for such hubris.

    I cannot resist closing with one last quote from the rich language of Havel himself:

    If we are certain that the planting was good and that we are watering regularly, we have no reason to be impatient. It is enough to realize that our waiting has meaning.

    Waiting that has meaning because it grows out of hope and not hopelessness, from faith and not despair, from humility toward the time of the world and not out of fear of its sublime tranquility, is accompanied not by boredom but by suspense. This kind of waiting is more than just waiting.

    It is life. Life as the joyous involvement in the miracle of Being.

    That sounds like a poet speaking, but it could be a programmer. And maybe the world would be a better place if all administrators thought this way. :-)


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

    May 20, 2005 10:59 AM

    Some Basic Principles

    I've been thinking a bit about how much the agile software development mindset affected my application for department head. When I first starting making notes for my statement of administrative philosophy, I jotted down some agile ideas: communication, people over processes, trust. Later, as I made notes for my presentation to the search committee, I again had a bullet for agile ideas, with feedback and continuous improvement appearing.

    In the end, many of these ideas played important roles in my application. Open communication and building trust became cornerstones of my philosophy. Feedback and continuous improvement became cornerstones of my plan for doing the job. I never got around to using the term "agility" in any of my materials, but its footprint was everywhere.

    My administrative philosophy rested on three points:

    • open communication
    • transparent decision making
    • respect for individuals

    These principles are essential to any healthy organization. They are perhaps even more important in an academic department, which consists of individuals who are both highly autonomous but also interdependent. They are especially important in a department fraught with lack of trust and persistent interpersonal conflict.

    These principles are also very much a part of the agile software movement. Communication fosters trust and enables feedback, which is how we learn to do our jobs better. People matter. What about transparent decision making? Only decisions are made openly can everyone involve contribute to the process. I believe that, in most situations, more ideas lead to better results. Furthermore, when someone disagrees with the decision that is made, at least the person can trust that the decision was made fairly and on principle.

    Some folks think that preferring people to processes means having little or no process. Others think that not tying themselves down with process (in administrative parlance "procedures and policies") frees them to adapt better to changing circumstances. Though I value adaptability, and people over process, I believe that appropriate process is essential to effective operation. XP isn't just a set of values or a set of principles; it is also a set of practices. These practices support the values and principles, make it possible for the team to live its values and embody its principles. I hope to help my department develop an appropriate set of procedures and policies. This will involve streamlining some of our existing procedures and implementing some new ones.

    Soon after I submitted my application materials, a related discussion developed on the XP discussion list. It started with a request for advice for navigating the waters of corporate politics and soon turned into a discussion of how the principles and practices of P can help us to create a good corporate environment. Along the way, someone said,

    Ok, those are good suggestions for navigating oneself through everyday relationships, in and out of work. But they are not techniques that are specific to XP.

    The answer to this assertion is both yes and no. Certainly, communication, feedback, continuous improvement, and the like are not specific to XP or any other agile methodology. But they are fundamental to the agile methods, and by making them explicit the agile methods help us to reflect and act on them more readily.

    As I told my colleagues and the other members of the search committee, I harbor no illusions that I will do this job perfectly. But I hope that, by making explicit the values that I hold and the principles that I think should guide our department, I hope to do a good job -- and to get better as I go along. This will depend in great part on the level of trust and communication that we are able to develop.


    Posted by Eugene Wallingford | Permalink | Categories: Managing and Leading, Software Development

    May 17, 2005 8:31 AM

    A Few Good Abstractions

    I just read Joel Spolsky's latest essay, Making Wrong Code Look Wrong. I'm all for Joel's goal of writing code that reveals the writer's intention, of making code transparent to the reader. And I'm sympathetic to his concerns about operator overloading in C++ and leaky abstractions. But the following paragraph exemplifies why I find his C-at-all-costs mentality somewhat uncomfortable:

    If you read Simonyi's paper closely, what he was getting at was the same kind of naming convention as I used in my example above where we decided that us meant "unsafe string" and s meant "safe string". They're both of type string. The compiler won't help you if you assign one to the other and Intellisense won't tell you bupkis. But they are semantically different; they need to be interpreted differently and treated differently and some kind of conversion function will need to be called if you assign one to the other or you will have a runtime bug. If you're lucky.

    Does anyone else think that Joel needs a really good abstraction here? If my program deals with two different kinds of string -- objects that are semantically different -- then I'd like to reflect that in more than a cryptic two-letter prefix. Classes may seem like overkill for these kinds of thing, but enums and Ada subtypes can be wonderful aids. Then, instead of relying solely on the programmer to read and interpret the prefixes, we could let our compilers and refactoring tools help us.

    Intention-revealing names are an important part of transparent code, but we should use languages and techniques that support our efforts, too.


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

    May 16, 2005 3:41 PM

    Start With A Box

    before you can think out of the box,
    you have to start with a box
    -- Twyla Tharp

    I've been reading Twyla Tharp's The Creative Habit, and that quote is the title of Chapter 5. As soon as I read it, I scribbled it down immediately on the note card I had tucked in the back of the book for just such occasions. The idea of "starting with a box" struck me in a particular way, and as I read the chapter I went through a journey from thinking that Tharp meant something else to thinking that, ultimately, we were onto the same idea. For Tharp, "the box" is as organizational system, a way of storing and managing her memory as she works on a new creative project. But the box is more than that -- it is really about preparation.

    Bobby Knight, the famous US college basketball coach, once said something along the lines, "The will to win is the most overrated desire in all of sports. Everybody has the will to win. What separates those who succeed is the will to prepare to win."

    I often encounter students who say that they can be successful contributors in the software industry despite their unwillingness to work hard to become really good programmers -- because they will be part of a team in industry. I guess they figure that some other member of the team is going to do the heavy lifting. My response to them is always the same: Why would a team want you as a member if you can't help with the most important product it produces? That's awfully presumptuous of you. For some folks, the desire not to program is borne out of a lack of interest in programming. But for many it grows out of a lack of success, and a consequent unwillingness to do the hard work needed to prepare for programming tasks.

    Most people can tell when they are unprepared for a job, though our egos sometimes hide the truth from us. Introductory students often come to my office with questions about a programming assignment, saying, "I know just what I want to do, but when I try to write the program I just can't say it in Java." (In earlier years, it was C++, or Pascal.) Again, my response is often the same: You don't really know what you want to say, or the program would come more easily. Tharp says so, too, using a journalist as her example:

    If his reporting is good, the writing will reflect that. It will come out quickly and clearly. If the reporting is shoddy, the writing will be, too. It will be torture to get the words out.

    Some may think that this all sounds bad for agile methodologies, which de-emphasize months of on-project preparation of requirements and design. But I think that this line of thought betrays a misunderstanding of agile methods, one reflected in the idea that they are reckless. Unprepared developers cannot write good software using an agile method. Agility doesn't mean not being prepared; it means letting your preparation work in concert with concrete steps forward to prepare you even better for what comes next.

    One thing I like about Tharp's chapter is that she doesn't stop at "be prepared". She reminds us that preparation is only preparation.

    The box is not a substitute for creating. The box doesn't compose or write a poem or create a dance step. The box is the raw index of your preparation. It is the repository of your creative potential, but it is not that potential realized.

    You still have to create! You have to write code. You have to pull your head out of design-land, out of the code library, out of the archives and actually begin writing code.

    Sadly, some people never get beyond the box stage in their creative life. We all know people who have announced that they've started work on a project ... but some time passes, and when you politely ask how it's going, they tell you that they're still researching. ... Maybe they like the comfort zone of research as opposed to the hard work of writing. ... All I know for sure is that they are trapped in the box.

    Some students do this, too. They work hard -- they really do -- but when the assignment comes due, there is no program to turn in; they never got around to actually producing something. And the program is the whole point of the assignment. Okay, okay, learning is probably the real point of the assignment, but you can't learn what you really need to learn until you write the program!

    This is where we can see a strong connection to the agile methods. They encourage us to be in a continuous state of writing small bits of code, testing and designing, cycling quickly between planning and producing.

    Tharp ends her chapters with exercises for the reader, activities that can help readers work on the idea they've just read about. The section at the end of "start with a box" consists of a single exercise, and it's not especially concrete,. But it does have an agile feel to it. When you are having a hard time getting out of the box, take a big leap somewhere in the project. Don't worry about the beginning or the end; just pick something, an especially salient point (or user story) and get to work. You never know where it will take you.

    "Getting out of the box" was one of the primary motivations for me starting my blog. I had boxes and boxes of stuff (metaphorical boxes, of course -- mine were either computer files or file folders stuffed with hastily written notes). But I had stopped taking the risk of putting my thoughts out in the public space. In that regard, this blog has been a huge success for me.


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

    May 05, 2005 11:16 AM

    Software Case Studies

    (I wrote a complete essay on this topic over the course of several hours on Monday and then, in a few swift seconds of haste, I did the unthinkable: I rmed it. Sigh. I don't know if I can reproduce that wondrous work of art, but I still have something I want to say, so here goes.)

    Last time, I wrote about how having a standard literary form can ease the task faced by writers and readers, including reviewers. I found this to be true of submissions to the OOPSLA Educators Symposium, and my colleague Robert Biddle found it to be true of submissions to the conference's practitioner reports track. From this starting point, Robert and I moved onto an ambitious idea.

    I closed my last entry with a cliffhanger: The unsupported claim that "the lack of a standard form is especially acute in the area of practitioner reports, which have the potential to be one most important contributions OOPSLA makes in the software world." This time, I'd like to talk about both parts of this claim.

    First, why is the lack of a standard literary form especially acute in the area of practitioner reports?

    Keep in mind that the authors of practitioner reports are software practitioners, folks in the trenches solving real problems. Most of these folks are not in the habit of writing expository prose to teach others or to share experiences -- their jobs are primarily to create software. Unlike most submitters to the Educators Symposium, the authors of practitioner reports are usually not academics, who typically have experience with expository writing and and can at least fall back on the literary forms they learned in publishing academic papers. (Sadly, those forms tend not to work all that well for sharing pedagogical experience.)

    Not having a standard literary form makes writing and reading practitioner reports that much harder. How can authors best communicate what they learned while building a software project? What ideas do readers expect to find in the paper? What's worse, because many software developers don't have much experience writing for a broad audience, not knowing how to go about writing a paper can create a considerable amount of fear -- and the result is that many practitioners won't even try to write a paper in the first place. It turns out that a standard literary form has another benefit: it provides comfort to potential authors, lowering the entry barrier to new writers.

    A great example of this effect is the software patterns community. Its popularization of a common and powerful literary form made it both possible and attractive to many practicing software developers to record and disseminate what they had learned writing programs. The software community as a whole owes an extraordinary debt for this contribution.

    So, I contend that the practitioner's track would benefit even more than the educators' track from the creation and widespread adoption of a standard literary form. (But I still hope that we educators will take steps to improve our lot in this regard.)

    Second, how do practitioner reports have the potential to be one most important contributions that OOPSLA or any other conference makes in the software world?

    Keep in mind that the authors of practitioner reports are software practitioners, folks in the trenches solving real problems. Researchers and methodologists can propose ideas that sound great in theory, but practitioners find out how well they work in the real world, where academic abstractions take a back seat to the messiness of real businesses and real people and real hardware. Even when researchers and methodologists make a good-faith effort to vette their ideas outside of their labs, it is difficult to recreate all the complexities that can arise when new adopters try implement the ideas in their organizations.

    The result is, we don't really know how well ideas work until they have been tried in the trenches. And practitioner reports can tell us.

    Sharing knowledge of a practical sort used to lie outside the domain of computer science and even software engineering, but the software patterns movement showed us that it could be done, that it should be done, and gave us some hints for how to do it. The potential benefit to practitioners is immeasurable. Before trying out XP, or migrating from Visual Basic to VB.Net, or integrating automated acceptance tests into the build cycle, a practitioner can read about what happened when other folks in the trenches tried it out. Usually, we expect that the ideas worked out okay in practice, but a good report can point out potential pitfalls in implementation and describe opportunities to streamline the process.

    Of course, academics can benefit from good practitioner reports, too, because they close the loop between theory and practice and point out new questions to be answered and new opportunities to exploit.

    Robert and I didn't talk much about what I've written so far in this entry, because we rather quickly moved on to Robert's bigger vision of what practitioner reports can be, one that presupposes the untapped value buried in this resource: the software case study.

    As Robert pitched it, consider NCSA Mosaic. Here is a program that changed the world. How was it built? What technical and non-technical problems arose while it was being written, and how did the development team solve them? Did serendipity ever strike, and how did they gain leverage? We can find the answers to all of these questions and more -- the creators are still around to tell the story!

    Case studies are a standard part of many disciplines. In business schools, students learn the how companies work by reading case studies. I remember well a management course I took as an undergraduate in which we studied the development of particular companies and industries through case studies. (Most of what I know about the soft drink industry came from that case book!) Of course, the law itself is structured around cases and webs of facts and relationships.

    We are fortunate to have some very nice case studies in computing. Knuth has written widely about his own programs such as Tex and his literate programming tools. Because Smalltalk is as much system as language, Alan Kay's The Early History of Smalltalk from History of Programming Languages II qualifies as a software case study. Other papers in the HOPL volumes probably do, too. I have read some good papers on Unix that qualify as case studies, too.

    Two of my favorite textbooks, Peter Norvig's Paradigms of AI Programming and Clancy and Linn's Designing Pascal Solutions, are built around sets of case studies. In the latter, the cases were constructed for the book; in the former, Norvig analyzes programs from the history of AI and reimplements them in Common Lisp. (You really *must* study this book.) I even used a case study book as a CS undergrad: Case Studies in Business Data Bases, by James Bradley. It's still on my bookshelf. More recently, the College Board's Marine Biology Case Study has received considerable attention in the AP and CS1 communities.

    So, if we believe that software case studies have merit, we find ourselves back in the trenches... How do we write them? Using an excellent case study as an exemplar would be a start. I suggest that any case study of value probably must tell us at least three things:

    1. In what context did we operate?
    2. What did we do?
    3. What did we learn?
    These elements apply to case studies of whole systems as well as to case studies of incremental changes to systems or process improvements. They are almost certainly part of the better practitioner reports presented at OOPSLA.

    Robert and I will likely work on this idea further. If you have any ideas, please share them. In particular, I am interested in hearing about existing and potential software case studies. Which of the case studies you've read do you think are the best exemplars of the genre? Which programs would you like to see written up in case studies?


    Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

    May 01, 2005 7:27 PM

    The Value of Standard Form in Evaluating Technical Papers

    Over lunch today, Robert Biddle and I discussed some thoughts we had after reviewing submissions to the OOPSLA Educators Symposium and practitioners reports track this year. Both of these tracks suffer from a problem that had never really occurred to me before this year: not having an accepted form for telling stories.

    If you read the proceedings of most computer science conferences, you will recognize that all the papers have a similar look and feel. This is the way that scientists in the domain communicate with one another. One function of a common form is to ensure an efficient exchange of information; having a common style means that readers immediately feel at home when they come to a paper. But there is a subtle secondary function, too. When you see a paper, you can tell whether the author is a part of the community or not.

    One of the the things that makes reviewing papers for the Educators Symposium tough is the variety of papers. With no standard, authors are left to mimic other papers or invent new forms that fit the story they want to tell. But every new form makes the program committee's job harder, too. How do we evaluate the contribution of a paper that looks and sounds different than any we've seen? What role should experimental validation of a teaching technique play? What role should an explanation of lessons learned, or a discussion of how to implement the technique at a different institution?

    Most frustrating for me as program chair were situations in which two reviewers evaluated the same paper in essentially complementary ways. This isn't a fault of the reviewers, because the community as a whole has not reached a consensus for what papers should be like. I suppose that one of my jobs as program chair is to guide this process closely, working with the program committee to give authors and reviewers alike a better sense of what we are looking for in submissions. The nifty assignment track that I introduced to the symposium last year was an attempt in this direction. I borrowed from a successful form used at recent SIGCSEs to encourage OO educators to tell the stories of their coolest and most engaging programming assignments. Having an expectation of what a nifty assignment should look like has led, I think, to a more satisfying evaluation process for these submissions.

    Maybe we as a community of educators need to work together to develop a standard way to tell teaching stories. Perhaps the greatest contribution of the software patterns community was to standardize the way practitioners and academics discuss the elements of program design and construction at a level above algorithms and data structures. As linguistic form, it enables communication in a way that was heretofore impossible.

    Notice here that a common literary form is more than a literary format. The patterns community is a good example of this. Even after a decade there are a number of accepted formats for writing patterns, some favored by one group of writers, some viewed as especially effective for patterns of a particular sort. The key to the pattern community's contribution is that it establishes expectations for the content of software patterns. I can comfortably read a pattern in almost any format, but if I can't find the context, the problem, the forces, and the solution, then I know the pattern has problems. The PLoP conferences play the role of enculturating pattern writers by helping them to learn the standard form and how to use it.

    The lack of a standard form is especially acute in the area of practitioners reports, which have the potential to be one most important contributions OOPSLA makes in the software world. I'll have more to say about this tomorrow.


    Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

    May 01, 2005 6:02 PM

    Planning for OOPSLA 2005

    OOPSLA 2005 logo

    Today and tomorrow, I am in San Diego for the OOPSLA 2005 spring planning meeting. I have the honor of chairing the Educators Symposium again this year and so am on the conference committee that makes OOPSLA happen. As usual, I'm impressed by the energy and talent of the people behind the scenes of OOPSLA. These folks are in the trenches scheduling talks and panels, tutorials and workshops, while simultaneously thinking about the future of software and where the conference can and should go in the future.

    the view from the OOPSLA 2005 conference site

    San Diego will be a great location for OOPSLA. We are at the Town and Country Resort, about 15 miles from downtown. The resort is more than just a hotel; the property includes several buildings of convention space, meeting rooms, and restaurants, not too mention the pools and outdoor gathering spaces. San Diego's temperate weather makes outdoor gatherings a real possibility. On our site tour earlier, a couple of us joked about holding software demonstrations poolside -- or even on the water, the "floating demo". We may as well surrender to the inevitable temptations that accompany meeting space adjacent to an outdoor pool.

    Last night, I had the pleasure of catching up with a current friend, a former student who now calls San Diego home. Kris picked me up, gave me a short driving tour of the area, and then took me off for dinner with another former UNI student, a former Waterloo native, and another Iowan. We talked sports, much to the chagrin of the ladies, and current campus goings-on. Dinner was at Quiigs Bar and Grill (5091 Santa Monica Ave) -- I had a wonderful grilled prawns dish.

    This morning, I checked out the running options from the hotel. I did an easy 10+-miler, heading west along Friars Road toward the beach. I never reached the beach but I did find an unexpected bonus: down near a marina off Sea World Drive, I came upon the start location for the Spring Sprint Triathlon and Biathlon. This is a little tri, a ¼-mile swim, a 9-mile bike, and a 3-mile run -- just within my reach. One of these days...

    Dick Gabriel and Ralph Johnson have a lot of neat ideas in the works for OOPSLA this year, including a track for essays, collocated symposia on wiki and Dylan, and the evolving Onward! track, which will debut a film festival. If you want to know what software people will be talking about in earnest three or four years from now, make sure to attend OOPSLA this year!


    Posted by Eugene Wallingford | Permalink | Categories: General, Software Development

    April 26, 2005 5:40 PM

    Importing Language Features

    While doing some link surfing yesterday, I ran across an old blog entry that has a neat programming languages idea in it: Wouldn't it be nice if we could encapsulate language features.

    The essay considers the difference between two kinds of complexity we encounter in programs. One is complexity in the language features themselves. First-class closures or call-with-current-continuation are examples. Just having them in a language seems to complicate matters, because then we feel a need to teach people to use them. Even if we don't, some programmer may stumble across them, try to use them, and shoot himself in the foot. Such abstractions are sometimes more than the so-called ordinary programmer needs.

    Another kind of complexity comes from the code we write. We build a library of functions, a package of classes, or a framework. These abstractions can also be difficult to use, or it may be difficult to understand their inner workings. Yet far fewer people complain about a language having too many libraries. (*)

    Why? Because we can hide details in libraries, in two ways. First, in order to use Java's HashMap class, I must import java.util.HashMap explicitly. Second, once I have imported the class, I don't really need to know anything about the inner workings of the class or its package. The class exposes only a set of public methods for my use. I can write some pretty sophisticated code before I need to delve into the details of the class.

    Alexander asks the natural question: Why can't we encapsulate language features in a similar way?

    Following his example, suppose that Sun adds operator overloading to Java but doesn't want every programmer to have to deal with it. I could write a package that uses it and then add a new sort of directive at the top of my source file:

    exposeFeature operatorOverloading;

    Then, if other programmers wanted to use my package, they would have to import that feature into their programs:

    importFeature operatorOverloading;

    Such an information-hiding mechanism might make adding more powerful features to a language less onerous on everyday programmers, and thus more attractive to language designers. We might even so languages grow in different and more interesting ways.

    Allowing us to reveal complex language features incrementally would also change the way we teach and write about programming. I am reminded of the concept of "language levels" found in Dr. Scheme (and now in Dr. Java). But the idea of the programmer controlling the exposure of his code to individual language features seems to add a new dimension of power -- and fun -- to the mix.

    More grist for my Programming Languages and Compilers courses next year...

    ----

    (*) Well, unless we want to use the language to teach introductory CS courses, of course.


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

    April 14, 2005 6:00 PM

    Accountability in the Classroom

    I sometimes like to think about ways in which learning to program is like learning to speak a foreign language. Usually, I focus on similarities between the two, to see whether I can use a correspondence to improve how I present an idea. In the middle of class this morning, a difference between the two occurred to me, and now I wonder how I can use this idea to improve my courses on a daily basis.

    The difference: Students of foreign language are more easily, more obviously, and more naturally held accountable for their level of preparation and their current state of proficiency than are students of computer programming.

    There has been a lot of discussion recently on the XP discussion list about the idea of accountability. Apparently, this concept is a driving force behind the "new P" described in Kent Beck's second edition of XP Explained. (I haven't had a chance to read it yet.) Much of the discussion concerns just what the word means. For me, Merriam-Webster's definition seems clear enough:

    ... an obligation or willingness to accept responsibility or to account for one's actions

    Am I obliged to account for my actions and take responsibility for them? Then I am being held accountable. Am I willing to account for my actions and take responsibility for them? Then I am being accountable. (*)

    My compiler holds me accountable for the correctness of the code I write. Each time I compile, I find out if my program is syntactically correct. My unit tests hold me accountable for the correctness of the code I write. Each time I run my tests, the green bar tells me that my program is functionally correct -- or the red bar tells me otherwise.

    Of course, I have to compile my program (at least once :-), but I am not obliged to write and run tests. One of the beauties of the agile programming practices is their demonstration of programmers' willingness to be held accountable for their time and their efforts. Obligation is supplanted by willingness, which opens the programmer to a new level of growth and performance.

    The compiler holds students accountable, too. As they learn and use new ideas, the compiler and their testing give them a measure of their accomplishments. So, the more practice they get -- the more code they write, the more projects they do -- the more feedback they get about their level of proficiency.

    In a typical computer science course, the instructor has only a small number of opportunities to gauge each student's development. In my most programming-intensive courses, I ask students to write only 12 programs for evaluation. That is quite a lot in a fifteen-week semester, but it's not enough. I wish that I could interact with each student every day, gauging preparation and proficiency, folding what I learn back into my instruction.

    What do I do now? I give students in-class exercises and discuss solutions every day. But some students work on the exercises only half-heartedly, if only because the absence of a keyboard and a compiler makes writing much code tedious. The discussion usually goes pretty well, but only a small subset of the students tend to participate actively. In class this morning, the inadequacy of my seemed especially obvious.

    So, my mind wanders... How would a course in spoken German or French differ? My in-class exercises and discussions pale in comparison to what a foreign language teacher can do so naturally: start a conversation with a student! A classroom discussion can grow quite easily to include many students, because each interaction with a student exposes the student's level of preparation and proficiency. Human conversation works that way.

    I can draw students into classroom discussions, but there is a big difference between writing code and talking about code, even talking about writing code. Someone can talk about code, or the ideas underlying code, even if they have difficulty writing the same.

    Students who are willing to account for their work sometimes find that they are not asked to. Students who need to be obliged to account for their work -- who would benefit greatly from being held more accountable -- come to count on not being so held.

    This line of thought was triggered today by my recognition that a couple of students came to class unprepared this morning. A couple said so, honest that they hadn't studied the reading assignment yet wanting to ask questions. A couple tried to blend in, relying on the fact that they would probably manage to get by. I wasn't in the mood to call them to account, but I was in the mood to think about the attitude itself.

    Owen Astrachan uses a great strategy for driving classroom interaction that has a side effect of holding students accountable for the time they spend in class on exercises. He passes blank transparencies out to groups of students working together on an exercise. They write their code on the transparencies. Finally Owen collects them and puts them on the projector for everyone to see and discuss. I don't know how often he makes the authors of a slide known to the class, or if he ever does In either case, I think that this strategy creates an environment in which students feel accountable.

    Some students are intrinsically motivated to learn. They hold themselves accountable no matter what the instructor or other students do. But some university students are not quite ready for this level of autonomy. Some instructors and universities seem to adopt an attitude of sink-or-swim, leaving it to students to figure out that they have to take control of their own learning. In some contexts, this is the right thing to do. Ultimately, each student is responsible for his or her own learning, accountable only to themselves.

    The role of a teacher, though, is more I think. Especially when working with children and even university freshmen, a teacher should help students learn to hold themselves accountable. I'd like to be able to readily recognize students who are struggling with material or not doing the work so that I can intervene. My German teachers could readily assess my level of preparation and proficiency by walking into the room, saying, "Guten Tag, Eugen! Wie geht's?" -- and then simply listening. Strategies like Owen's may be the best we can do in computer science, so we need to share them when we have them.

    When you have to write your code on a slide and give it to the professor for possible display in front of the whole class, you have a built-in accountability partner. The success of groups such as Alcoholics Anonymous is founded in large part on relationships in which one person helps another to hold himself accountable. Sometimes, just telling someone else that you are quitting smoking or trying to curb your profanity can be enough external support to do a better job. Who wants to disappoint a friend, or look weak? You might even tell the Internet.

    When a student signs up for a formal course in a topic, one element of the action is to put themselves in a formal accountability relationship. The teacher and the classmates act as accountability partners. Obviously, this isn't the only responsibility of a teacher, nor even the most important, but it is a good part of the deal for the learner.

    This is wandered a bit from thought that triggered all this, which was something like, "If a student went to a French class as unprepared as some students come to their programming classes, they would be found out quickly. That would straighten them up!" (In moments of weakness, I sometimes surrender to temptation.) But ultimately I am motivated by a desire to do a better job as a teacher.

    It occurs to me that I have written a similar entry before...

    ----

    (*) I've not gotten into the mailing list discussion much, but this seems to be what Kent asks of himself and other programmers. It seems pretty reasonable to me, and at the heart of many agile development practices.


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

    April 11, 2005 9:38 AM

    Agile Start-Ups

    Agile methods aren't just for managing individual projects. They may be an essential component in a start-up company's long-term strategy.

    In his recent essay, How to Start a Startup, Paul Graham talks about how important the choice of type of software to write is for the success of a start-up. He suggests that a start-up write software for smaller companies, where the competition and sums of money are smaller. But then he says:

    They're the more strategically valuable part of the market anyway. In technology, the low end always eats the high end. It's easier to make an inexpensive product more powerful than to make a powerful product cheaper. So the products that start as cheap, simple options tend to gradually grow more powerful till, like water rising in a room, they squash the "high-end" products against the ceiling.

    He cites several examples from the recent history of technology, from digital cameras to desktop publishing to Henry Ford and the automobile. In any case, this sounds like a harnessing of simplicity-first and piecemeal growth as a business strategy for product and market selection.

    Once you know the kind of product you want to sell, you have to find out what customers want. How best to do that?

    ... get a version 1 out as soon as you can. ... The only way to make something customers want is to get a prototype in front of them and refine it based on their reactions.

    Graham calls the alternative a "Hail Mary" strategy: do a lot of planning, generate a big design up front, develop a finished working product -- and then pray that enough customers will pay you for it.

    Graham's own start-up benefited greatly from its agility. ViaWeb's initial target market consisted of web consultants, but it soon learned that its software made the consultants disposable which, needless to say, didn't endear the idea to the consultants. As a result of early experience with customers, the company shifted its market focus to small merchants and its software focus to ease of use: making a product that users could actually use to do their job better. The customer played a central role in defining and refining the requirements of the project.

    Graham is not an "agile guy", and from my reading of him I'd guess he's a bit suspicious of all the hype around agile methods. Lisp hackers and Smalltalk hackers have long had the patterns that make up the agile development methods. It seems that an agile mindset on the technology side of things is compatible with an agile mindset on the business side of things -- and perhaps crucial to the viability of new companies.

    While I'm on the topic of Graham's essays, if you are a student, you should definitely read his recent articles Undergraduation and What You'll Wish You'd Known. They give an interesting perspective on how to approach your high school and college years. Heck, even if you aren't a student you might well enjoy them.


    Posted by Eugene Wallingford | Permalink | Categories: Software Development

    April 08, 2005 5:45 PM

    On Introducing Agile Methods to Programmers

    After teaching Agile Software Development to university juniors and seniors last semester for the second time, and introducing test-driven design early in CS II this semester, I am coming to a deeper appreciation for how much agile methods require a change in deeply-rooted habits.

    It is easy for a person who have already developed a new habit (read: me) to walk into classroom and make assumptions about what will motivate students to change their habits. It doesn't take long before new practices become uncomfortable enough that a learner prefers to drop back to what she knows best. In CS II, students soon bump into objects that are hard for them to test, file processors and GUIs among them. And, as Bill Caputo points out, the benefits of TDD don't just happen, "you have to want to find a way to structure the code so that it can be tested without resorting to resources beyond the test." That can be hard for any programmer learning to do TDD, and it's harder for students who are still learning how to program at all.

    I've been thinking been thinking about how to introduce these new ideas more effectively in the classroom. We university educators have something to learn from industry trainers who introduce agile methods to their clients. Brian Marick's recent article describes advice he gives to clients who ask him for help. Some of the details don't apply to my usual situation, such as "read Michael Feathers' wonderful Working Effectively with Legacy Code". Not that the book isn't wonderful -- it is! It's just that my students aren't usually ready for this book yet. But the more general advice -- work on developing habits deliberately, focus on test writing before refactoring, encourage collective learning and sharing -- can help me. I need to find ways to implement this advice in my context.

    I suppose that my experience as an agile methods actor tells me that I have something to learn from this book, too. But my students aren't always fearless, and neither am I.


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

    April 07, 2005 7:49 AM

    Software in Negative Space

    Drawing on the Right Side of the Brain

    I started college as an architecture major. In the first year, architecture students took two courses each semester: Studio and Design Communications Media. The latter had a lofty title, but it focused on the most basic drawing skills needed in order to communicate ideas visually in architecture. At the time, we all considered it a freehand art class, and on the surface it was. But even then I realized that I was learning more.

    The textbook for DCM was Betty Edwards's Drawing on the Right Side of the Brain. It is about more than drawing as a skill; it is also about drawing out one's creativity. Studying this book, for the first time I realized that what we do in life depends intimately on what we see.

    Often, when people try to draw a common object, such as a chair, they don't really draw the chair in front of them but rather some idealized form, a Chair, seen in their mind's eye. This chair is like a Platonic ideal, an exemplar, that represents the idea of a chair but is like no chair in particular. When the mind focuses on this ideal chair, it stops seeing the real chair in front of it, and the hands go onto cruise control drawing the ideal.

    The great wonder in Edwards's book was that I could learn to see the objects in front of me. And, in doing so, I could learn to see things differently.

    Drawing on the Right Side of the Brain introduces a number of techniques for seeing an object, for the first time or in a new way, with exercises aimed at translating this new vision into more realistic depictions of those items on paper or canvas.

    a freehand rendition of the Japanese character 'ma'

    I recently found myself thinking again about one of the techniques that Edwards taught me, in the realm of software. Alan Kay has often said that we computer computer scientists focus so intently on the objects in our object-oriented programming that we miss something much more important: the space between the objects. He speaks of the Japanese word ma, which can refer to the "interstitial tissue" in the web of relationships that make up a complex system. On this view, the greater value in creating software lies in getting the ma right.

    This reminds me of the idea of negative space discussed in Edwards's book. One of her exercises asked the student to draw a chair. But, rather than trying to draw the chair itself, the student is to draw the space around the chair. You know, that little area hemmed in between the legs of the chair and the floor; the space between the bottom of the chair's back and its seat; and the space that is the rest of the room around the chair. In focusing on these spaces, I had to actually look at the space, because I don't have an image in my brain of an idealized space between the bottom of the chair's back and its seat. I had to look at the angles, and the shading, and that flaw in the seat fabric that makes the space seem a little ragged.

    In a sense, the negative space technique is merely a way to trick one's mind into paying attention to the world in a situation when it would prefer to lazily haul out a stock "kitchen chair" image from its vault and send it to the fingers for drawing. But the trick works! I found myself able to draw much more convincing likenesses than I ever could before. And, if we trick ourselves repeatedly, we soon form a new habit for paying attention to the world.

    This technique applies beyond the task of drawing, though. For example, it proves quite useful in communicating more effectively. Often, what isn't said is more important than what is said. The communication lies in the idea-space around the words spoken, its meaning borne out in the phrasing and intonation.

    The trigger for this line of thought was my reading an entry in Brad Appleton's blog:

    ... the biggest thing [about software design] that I learned from [my undergraduate experience] was the importance of what I believe Christopher Alexander calls "negative space", only for software architecture. I glibly summarized it as

    There is no CODE that is more flexible than NO Code!

    The "secret" to good software design wasn't in knowing what to put into the code; it was in knowing what to leave OUT! It was in recognizing where the hard-spots and soft-spots were, and knowing where to leave space/room rather than trying to cram in more design.

    Software designers could use this idea in different ways. Brad looks at the level of design and code: Leave room in a design, rather than overspecifying every behavior and entity that a program may need. But this sense of negative space is about what to leave out, not what to put in. The big surprise I had when using Edwards's negative space technique was that it helped me put the right things into my drawings -- by focusing on their complement.

    I often think that the Decorator design pattern embodies negative space: Rather than designing new classes for each orthogonal behavior, define objects as behaviors with receptacles into which we can plug other objects. The negative space in a Decorator is what makes the Decorator powerful; it leaves as many details uncommitted as possible while still defining a meaningful behavior. I suppose that the Strategy pattern does the same sort of thing, turned inside out.

    Maybe we can take this idea farther. What would it be like to design a program not as a set of objects, or a set of functions, but as Kay's ma? Rather than design actors, design the spaces in between them. Interfaces are a simple form of this, but I think that there is something deeper here. What if all we defined were an amorphous network of messages which some nebulous agents were able to snatch and answer? Blackboard architectures, once quite common in artificial intelligence, work something like this, but the focus there is still on creating knowledge sources, not their interactions. (Indeed, that was the whole point!)

    Even crazier: what it would be like to design software not by focusing on the requirements that our users give us, but on the "negative space" around them? Instead of adding stuff to a concoction that we build, we could carve away the unwanted stuff from a block of software, the way a sculptor creates a statue. What would be our initial block of granite or marble? What would the carving feel like?

    Whether any of these farfetched ideas bears fruit, thinking about them might be worthwhile. If Alan Kay is right, then we need to think about them.

    Edwards's negative space technique makes for a powerful thinking strategy. Like any good metaphor, it helps us to ask different questions, ones that can help us to expose our preconceptions and subconscious biases.

    And it could be of practical value to software designers, too. The next time you are stumped by a design problem, focus on the negative space around the thing you are building. What do you see?


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

    April 04, 2005 3:58 PM

    Agile Methods in the Dining Room

    I've written about using agile software principles in my running. Now Brian Marick applies the idea of Big Visible Charts as a motivational technique for losing a few pounds.

    The notion that practices from agile software development work outside of software should not surprise us too much. Agile practices emphasize individuals and interactions, doing things rather than talking about things, collaboration and communication, and openness to change. They reflect patterns of organization and interaction that are much bigger than the software world. (This reminds me of an idea that was hot a few years ago: design patterns occur in the real world, too.)

    Oh, and good luck, Brian! I know the feeling. Two years ago, I had broken the 190-pound barrier and, despite recreational jogging, felt soft and out of shape. By exercising more and eating less (okay, exercising a lot more and eating a lot less), I returned to the healthier and happier 160-pound range. I'll keep an eye on your big visible chart.


    Posted by Eugene Wallingford | Permalink | Categories: General, Patterns, Running, Software Development

    April 01, 2005 9:07 AM

    Reading to Write

    Yesterday morning, one of my students told me that he was thinking of changing his major. It turns out that he was English major before switching to CS, and he is thinking about switching back. We got to talking about the similarities and differences between the majors and how much fun it would be to major in English or literature.

    Some salesman I am! We need more CS majors, so I should probably have tried to convince to stay with us. Discussing the relative value in the two majors was beyond the scope of our short discussion, though, and that's not really what I want to write about.

    The student mentioned that he knew of other folks who have bounced between CS and English in school, or who have studied in one field and ended up working in the other. I wasn't too surprised, as I know of several strong students in both disciplines who have performed well in the other and, more importantly, have deep interests in both. Writing and programming have a lot more in common than most people realize, and people who love to communicate in written form may well enjoy programming.

    I myself love to read books by artists about their crafts. The "recommended reading list" that I give to students who ask includes two books on writing: William Zinsser's On Writing Well and Joseph Williams's Style. But I've enjoyed many wonderful books on writing over the years, often on recommendation from other software developers...

    • several of Zinsser's other books,
    • Natalie Goldberg's Writing Down the Bones
    • Richard Hugo's The Triggering Town
    • Scott Russell Sanders's Writing From The Center
    • Anne Lamott's Bird by Bird
    • Annie Dillard's The Writing Life
    • E.L. Doctorow's Reporting the Universe

    Each has taught me something about how to write. They have helped me write better technical papers and better instructional material. But I have to admit that I don't usually read these books for such practical reasons. I just like to feel what it's like to be a writer: the need to have a voice, the passion for craft. These books keep me motivated as a computer scientist, and they have indirectly helped me to write better programs.

    Writers aren't the only artists whose introspective writing I like to read. The next book to read on my nightstand is Twyla Tharp's The Creative Habit. Dance is much different than fiction, but it, too, has something to teach us software folks. (I seem to recall a dinner at PLoP many years ago at which Brad Appleton suggested dance as a metaphor for software development.)

    When I started writing this essay, I thought that it would be about my recommended reading list. That's not how it turned out. Writing is like that. So is software development sometimes.


    Posted by Eugene Wallingford | Permalink | Categories: Computing, Software Development

    March 09, 2005 3:25 PM

    The Capacity for Experience

    'Men are wise in proportion, not to their experience,
    but to their capacity for experience.
    -- George Bernard Shaw

    Yesterday in my CS II course, my students and I discussed some of the possible designs for their current assignment and how the decisions each programmer makes will change the nature of the program each writes. Later in the day, I received an e-mail message from one of the students. It ended:

    P.S. Got home today, and started lab over, got to the same spot as before in under 2 hours, code is much easier to read and look at! Thanks.

    My immediate thought was, "This guy has what it takes."

    When I encounter such students, I don't need to see their code to know that they will eventually become good software developers, if their interest in computing stays strong. They have the most important characteristic of any learner: the capacity for experience.

    This idea seems to be a theme running through many of my own experiences and reading lately. First, I remember reading this piece by Johanna Rothman. It distinguishes "several years of experience" from "the same year of experience several times". Johanna's blog focuses on hiring technical people, and she suggests questions you can ask job applicants in order to decide which kind of person they are. A candidate question is "Tell me about the first time you did that kind of work."

    People who know the difference between the same year of experience multiple times and multiple years of experience have answers to these questions. People who do the same thing year-in, year-out don't have good answers.

    I see the same thing in college students. Some students would use Johanna's question as a springboard into an engaging conversation about what they learned in the process of that first time. We end up talking not only about the first time but many times since. Even in the conversation we both may end up learning something, as we complement one another's experiences with our own.

    Other students look at me unknowingly. They are often the ones who are still hitting the delete key 67 times instead of having taken the time to learn dd in vi (ctrl-k or something similar for emacs devotees :-).

    Then I re-read Malcolm Gladwell's The Physical Genius after running into Pragmatic Dave's short note on making mistakes. I first read Gladwell's article a few years ago when someone first introduced me to his writing, but this time time it struck me in my experiential theme. Not only do these physical geniuses prepare obsessively, they also share a deep capacity for recognizing their own mistakes and learning from them. Rather than hide their errors behind a wall of pride, they almost revel in having recognized them and overcome them. They use their experiences to create experience.

    Dave quotes Gladwell quoting Charles Bosk, who had tried to find a way to distinguish good surgeons from the not so good:

    In my interviewing, I began to develop what I thought was an indicator of whether someone was going to be a good surgeon or not. It was a couple of simple questions: Have you ever made a mistake? And, if so, what was your worst mistake? The people who said, 'Gee, I haven't really had one,' or, 'I've had a couple of bad outcomes but they were due to things outside my control' - invariably those were the worst candidates. And the residents who said, 'I make mistakes all the time. There was this horrible thing that happened just yesterday and here's what it was.' They were the best. They had the ability to rethink everything that they'd done and imagine how they might have done it differently."

    Johanna Rothman would probably agree with Bosk's approach.

    Some folks don't seem to have the mindset of Bosk's successful surgeons, at least by the time they reach my classroom, or even when they reach the workplace. In that same CS II class yesterday, I sensed that a few of the students were uncomfortable with the notion that they themselves had to make these design decisions. What if they made the wrong choice? I suggested to them that none of the choices was really wrong, and that each would make some things easier and other things harder. Then I told them that, even if they came to rue their choice of an Object[] over a Vector, that's okay! They can rest assured that the alternative would have been rueful in another way, and besides they will have learned something quite useful along the way. That was no comfort at all to the students who aren't uncomfortable.

    So much of what students learn in college courses isn't listed in the course catalog description. I hope I can help some of my students to learn new habits of mind in this regard. Developing a capacity for experience is more important than learning the habit of TDD.

    Then again, software people with a capacity for experience seem to gather in places where practices like TDD become a focal point. Patterns. Pragmatic programming. XP. Agile software development. All grew out of folks reflecting on their successes and failures with humility and asking, "How can we do better?" The student who sent me that e-mail message will fit in quite nicely.


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

    March 04, 2005 4:06 PM

    Creativity, Productivity, Discipline, Flow

    When I first learned that Mihaly Csikszentmihalyi (whose name is pronounced 'me-HI chick-SENT-me-hi') would be speaking here, I hoped that he might be able to help me to understand better the role of flow in learning and programming. These ideas have been on mind occasionally through experience with the Suzuki method of piano instruction and Alan Kay's comments on the same in his talks at OOPSLA. When I left the lecture room last night, I was a bit disappointed with the talk, but as time passes I find that its ideas have me thinking...

    Csikszentmihalyi opened by explaining that his interest creativity began as a child in Hungary. Many of his family members were artists and lived rich lives, but most people he knew lived "fragile lives", all too sensitive to the vagaries of war and economy. He chose to study creative people to see how everyone can live a better life, a less fragile life, a beautiful life.

    Through his studies, he came to distinguish "small c" creativity and "big C" Creativity. To some degree, we all are creative in the small-c way, doing things that enrich our own lives but do not receive recognition from the outside world. Big-c creativity is different -- it produces ideas that "push our species ahead". At first, the use of recognition to distinguish quality of creativity seemed incongruent, but I soon realized that creative ideas take on a different form when they move out into the world and mingle with the rest of a domain's knowledge and culture. Csikszentmihalyi came back to this nugget later in his talk.

    Big-C creativity is rare. Defining it is impossible, because every definition seems to over- or underconstrain something essential to creativity from our own experience. But Csikszentmihalyi asserted that society values Creativity for its ability to transform people and cultures, and that it drives creative people to "pursue to completion" the creative act.

    To support his claim of scarcity and to begin to expose the culture's role in recognizing creativity, Csikszentmihalyi presented some empirical studies on the relationship between individuals' contributions and their disciplines. The first was the so-called Lotka Curve. Alfred Lotka was an eminent biophysicist of the early 1900s. In the mid-1920s, he identified a pattern of publication in scientific journals. Roughly 60% of all people who publish publish only one journal article. The percentage of people who publish two articles is much smaller, and the percentage of people who publish more articles falls rapidly as the number of articles increases. This creates an L-shaped graph of the function mapping number of publications onto the percentage of contributors at that level.

    The second was Price's Law. He referred not to the law from physics, which describes a model of gravitational collapse and the "strong cosmic censorship conjecture" (a great name!), but to another model of contribution: one-half of all contributions in any domain are made by the square root of all potential contributors. According to Csikszentmihalyi, Price derived his law from data in a large variety of domains.

    I do not have citations to refereed publications on either of these models, so I'm at the speaker's mercy as to their accuracy. The implication is substantial: in any group, most people contribute little or nothing to the group. Perhaps that is stated too strongly as a generalization, because a single publication or a single piece of art can make a major contribution to the world, belying the creator's point on the Lotka Curve. But if these models mean what Csikszentmihalyi claims, culture and even narrower domains of discourse are driven forward by the work of only a few. I don't think that this will alarm too many people. It sounds just like the long tail and power law that dominates discussion of the web and social networks these days.

    Finally Csikszentmihalyi got around to describing his own results. Foremost was this model of how creativity and ideas affect the world:

    The culture transmits information to people. Some people are happy to keep it at that, to absorb knowledge and use it in their lives. These folks accept the status quo.

    The creative person, though, has the idea that he can change the world. He produces a novelty and pushes it out for others see. Only a small percentage of folks do this, but the number is large enough that society can't pay attention to all of the novelties produce.

    A field of discourse, such as an academic discipline or "the art world", selects some of the novelties as valuable and passes them onto the culture at large with a seal of approval. Thus the field acts as a gatekeeper. It consists of the critics and powerbrokers esteemed by the society.

    When there doesn't seem to be enough creativity for rapid change in a domain, the problem is rarely with the production of sufficient ideas but in the field's narrow channel for recognizing enough important novelties. I suppose that it could also come back to a field's inability to accurately evaluate what is good and what isn't. The art world seems to go through phases of this sort with some regularity. How about the sciences?

    Csikszentmihalyi has devoted much of his effort to identifying common characteristics in the personalities of creative individuals. The list of ten characteristics he shared with his audience had some predictable entries and some surprises to me:

    1. great energy, "bounce"
    2. convergent thinking
    3. playfulness, openness to new experience
    4. imagination, fantasy
    5. extroverted, sociable
    6. ambitious, proud, creative
    7. sensitive, feminine (not particularly aggressive)
    8. traditional, conservative (not particularly rebellious)
    9. attached, involved, passionate
    10. suffering, vulnerable, insecure (not particularly joyful, strong, or self-confident)

    I'm not surprised to see high energy, openness to new experience, ambition, passion, ... on the list. They are just what I expect in someone who changes the world. But Numbers 7, 8, and 10 seemed counterintuitive to me. But some reflection and further explanation made sense of them. For example, #7 is a simplification, on the notion that historically many of the biggest contributors of ideas and works of art to society have been men. And these creative men tend to have personality traits that society usually associates with women. This element works the other way, too. Major female contributors tend to have personality traits that society usually associates with men. So this element might more accurately be labeled outside society's gender expectations or somesuch.

    (And before anyone feels the needs to rain flame down on me a lá the recent Larry Summers fiasco, please note that I recognize fully the role that socialization and and other social factors play in the documented history of male and female contributions to the world. I also know that it's just a generalization!)

    Convergent thinking and conservatism also seemed out of place on the list, but they make sense when I consider Csikszentmihalyi's systemic model of the flow of contributions. In order to affect the world, one must ordinarily have one's idea vetted by the field's powerbrokers. Rebelliousness isn't usually the best means to that end. The creative person has to balance rule breaking with rule following. And convergence of thought with ideas in the broader culture increases the likelihood of new ideas being noticed and finding a natural home in others' minds. Ideas that are too novel or too different from what is expected are easy to admire and dismiss as unworkable.

    This talk didn't deal all that much with Csikszentmihalyi's signature issue, flow, but he did close with a few remarks from folks he had studied. Creators seem to share a predilection to deep attention to their work and play. In such moments, the ordinary world drops beyond the scope of their awareness. He displayed a representative quote from poet Mark Strand:

    The idea is to be so ... so saturated with it that there's no future or past, it's just an extended present in which you're, uh, making meaning. And dismantling meaning, and remaking it.

    I'm guessing that every programmer hears that quote and smiles. We know the feeling--saturation, making meaning.

    Csikszentmihalyi closed his talk with a couple of short remarks. The most interesting was to refute the common perception that Creative people are prone to living dissolute lives. On the contrary, the majority of the folks he has studied and interviewed have been married for all of their adult lives, have families, participate at their churches in in civic organizations. They have somehow come to balance "real life" with sustained episodes of flow. But, true to Personality Trait #10 on the list above, they all feel guilty about not having spent more time with their spouses and children!

    (At this point, I had to leave the talk just as the question-and-answer session was beginning. I had to pick my daughters up from play rehearsal. :-)

    This talk has led me to a few thoughts...

    • If the world is changed by a rather small number of contributors, where does that leave the rest of us? Certainly, we can be creative and improve our own lives as a result. But we can also improve the lives of those around us. And we shouldn't think that we will never have effects beyond our local world. Contributions of the small sort can sometimes lead to effects we never anticipated.

    • Csikszentmihalyi mentioned the significant role that luck plays in both the creative act and its entry into the culture. I liken this to making money in the stock market. Most of the growth in the market occurs on a few days of extreme growth; if you want to make money, you have to be in the market when those unpredictable days pass by. You can try to time the market, but the risk of being out of the market for a few days is much higher than the marginal increase you may achieve. Likewise, moments of inspiration happens sometimes when you least expect them. The key is to be active, engaged, and aware. If you are doing when inspiration comes, you will be able to capitalize. If you are dawdling or wasting time on the web, then you'll miss it.

      And, to the extent that we can stimulate an environment in which the creative moment can occur, you need to active, engaged, and aware. That is a major component of the success that we see in highly productive people.

    • I believe that a person can cultivate the personality traits shared by creative people. Some are easier to practice than others, and what's toughest to cultivate differs from person to person. I'm sociable but not extroverted, so I have to work at engaging people more than some other folks. And, while I think I'm relatively insecure compared to other academics, I don't naturally expose myself as vulnerable. But these are habits as much as anything, and they can be unlearned. Some folks may have gifts that give them a head start to being creative and productive, we all can be, if we choose to work hard to change.

    • What about the agile software community? The agile approaches encourage "small" practices, the sort of small-c creativity that can improve the developer's life and the developer's company. But they can also improve the lives of clients. And I believe that the cumulative effect of simple practices, can be a qualitative difference in how we behave -- from which large-c Creativity can emerge. If a person has the right mindset, they can sometimes make great leaps in understanding.

    • Many people have engaged in practices we now call agile for decades. But a select few decided to "go public", to try to change how software is built in the world. They sought to bring social attention to these ideas and to build a new community of discourse. The folks who started the Agile Alliance, the folks who have tried to take these ideas into the testing community... they are engaging in big-c Creativity, even as it emerged from lots of little acts -- and even if they hadn't planned to.

    • I suspect some of the leaders of the agile movement did start out with the intention of changing the world. Guys like Kent Beck, Ward Cunningham, and Alistair Cockburn have a vision that they want to bring to the community as a whole. I admire them for their ambition and energy. I also admire that they are willing to learn in the public and adapt. For example, Kent learned a lot in writing and promoting XP Explained, and now he has written a second edition that embodies what he has learned -- and he tells readers upfront that it's different, and that he has learned.

    With so many great books to read, now that I have seen Csikszentmihalyi speak, I doubt that I'll read "Flow" any time soon. But I think its ideas will continue to percolate in mind.


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

    February 16, 2005 11:18 AM

    Agile Moments

    When I taught a course on Agile Software Development last semester, I fell into a habit of beginning the first class each week with a segment called "Agile Moments". Think of Saturday Night Live's old Deep Thoughts, by Jack Handy, only on a more serious plane. I'd gather up one or two interesting ideas I'd encountered in the previous week from posts to the XP mailing list, blogs I'd read, or projects I was working on. Then I'd pull out a provocative or entertaining quote and use that to launch into a discussion of the idea with my students. This seemed like a good way to share topical information with my students while showing them that they could enter into real conversations about how to write programs. It also reminded my students that I am always reading what others are writing about agile software, and that they could, too.

    Anyway, I've been so busy planning for ChiliPLoP 2005, for which I am program chair and a Hot Topic leader, and SIGCSE 2005, at which I am co-leading a workshop with Joe Bergin, that I haven't been writing a lot here. But I do find myself having Agile Moments, so let me share them with you.

    Programming and Testing

    Patrick Logan has a nice article on speaking in objects, which suggests that programming is best thought of as a dialog with the computer. The pithy quote that stands out in this article is one he attributes to Ward Cunningham:

    It's all talk until the tests run.

    We all know that's true.

    Simple Design

    Grady Booch is spending a lot of time in his considerable library as hew works on his Handbook of Software Architecture. Yesterday he wrote about one of his favorite books, John Gall's Systemantics. Based on Grady's recommendation, I just picked this book up from our library. Among other things, Gall argues that successful large systems invariably come from successful small systems. This reminds me of agile development's emphasis on piecemeal growth and evolutionary design through tests and refactoring. One of Gall's quotes captures one of the primary motivations of the agile approaches:

    Bad design can rarely be overcome by more design, whether good or bad.

    This points out the big risk of Big Design Up Front: If we get it wrong, we likely have sunk our project. It is hard to recover from a bad design.

    Of course, in true Agile Moments fashion, I also encountered a cautionary tale about evolutionary design. Martin Fowler warns of the risks of Abundant Mutation, which can occur with large teams when many sub-teams attack a common issue in different ways, or with smaller teams when a stream of newcomers continually join a project in mid-stream and take unfinished code in different directions. Martin reminds us that "evolutionary design requires attention, skill, and leadership".

    Continuous Refactoring

    Blaine Buxton recently posted a quote worthy of being an agile slogan:

    Code removed is code earned.

    Refactoring may end up shrinking the size of your system, but it is a net addition in the quality of your system. You earn the ability to add the next requirement more easily, as well as the ability to understand the program more easily.

    Blaine's quote reminded me of my favorite quote about the joys of refactoring, which showed up in a blog entry I wrote long ago:

    The only thing better than a 1000-line of code weekend is a minus 1000-line of code weekend.

    -- Brian Foote

    Brian could make a fine living as a writer of slogans and jingles!


    Posted by Eugene Wallingford | Permalink | Categories: Software Development

    February 11, 2005 4:17 PM

    Taking Projects to an Extreme

    One of my favorite TV shows back when I was little guy in the 1970s was The Paper Chase. It was a show about a group of law students, well, being law students. It was based on a 1973 movie of the same name. It's not the sort of show that tends to hang around the TV schedule very long; it lasted only a year or two on network television. Even still, I fell in love with the quiet drama of university life while watching this show.

    Whether you remember the show or not, you may well know its most famous character, Professor Charles W. Kingsfield, Jr., played with panache by the eminent John Houseman. Professor Kingsfield was in many ways the archetype for the brilliant scholar and demanding yet effective university teacher that one so often sees on film. Growing up, I always hoped that I might encounter such a professor in my studies, certain that he would mold me into the great thinker I thought I should be. In all my years of study, I came across only one teacher who could remind me of Kingsfield: William Brown, an old IBM guy who was on the faculty at Ball State University until his retirement. Many professors demanded much of us, and some were brilliant scholars, but only Dr. Brown had the style that made you feel honor in the fear that you might not meet his standard. I had plenty of great professors at Ball State, but none like Dr. Brown.

    Why this reminiscence on a Friday afternoon 20 or 25 years later? I thought of John Houseman and a particular episode of The Paper Chase yesterday afternoon. The episode revolved around a particularly laborious assignment that Kingsfield had given his Contracts class. (Kingsfield made contract law seem like the most lively intellectual topic of all!) The assignment required students to answer one hundred questions about the law of contracts. Some of these questions were relatively routine, while others demanded research into hard-to-find articles and journals from way back. Of course, students worked together in study groups and so shared the load across four or five people, but even so the assignment was essentially impossible to complete in the time allotted.

    While sharing their despair, our protagonists -- Mr. Ha-a-a-rt and his study group -- stumbled upon a plan: why not share the load with other study groups, too? Soon, all the study groups were working out trades. They couldn't trade answers one for one, because some groups had worked on the hardest questions first, so the answers they offered were more valuable than those of a group that had cherry-picked the easy ones first. By the end of the episode, the groups had drawn up contracts to guide the exchange of information, executed the deals, and submitted a complete set of answers to Kingsfield.

    As the students submittted the assignments, some worried that they had violated the spirit of individual work expected of them in the classroom. But Hart realized that they had, in fact, fulfilled Kingsfield's plan for them. Only by negotiating contracts and exchanging information could they conceivably complete the assignment. In the process, they learned a lot about the law of contracts from the questions they answered, but they had learned even more about the law of contracts by living it. Kingsfield, the master, had done it again.

    So, why this episode? Yesterday I received an e-mail message from one of our grad students, who has read some of my recent entries about helping students to learn new practices. (The most recent strand of this conversation started with this entry.) He proposed:

    ... I wonder if you have considered approaches to teaching that might include assigning projects or problems that are darned-near unsolvable using the methods you see the students using that you wish to change? ... you can't really force anyone to open up or see change if they don't feel there is anything fundamentally wrong with what they are doing now.

    This is an important observation. A big part of how I try to design homework assignments involves finding problems that maximize the value of the skills students have learned in class. Not all assignments, of course; some assignments should offer students an opportunity to practice new ideas in a relatively stress-free context, and others should give them a chance to apply their new knowledge to problems that excite them and are methodology-neutral.

    But assigning problems where new practices really shine through is essential, too. Kingsfield's approach is a form of Extreme Exercise, where students can succeed only if they follow the program laid out in class.

    In university courses on programming and software development, this is a bigger challenge than in a law school. It is Conventional Wisdom that the best programmers are ten or more times more productive than their weakest colleagues. This disparity is perhaps nowhere wider than in the first-year CS classroom, where we have students everywhere along the continuum from extensive extracurricular experience and understanding to just-barely-hanging-on in a major that is more abstract and demanding than previously realized. Kingsfield's approach works better with a more homogeneous student body -- and in an academic environment where the mentality is "sink or swim", and students who fail to get it are encouraged to pursue another profession.

    I still like the idea behind the idea, though, and think I should try to find an exercise that makes, say, test-driven design and refactoring the only real way to proceed. I've certainly done a lot of thinking along these lines in trying to teach functional programming in my Programming Languages course!

    Practical matters of educational psychology confound even our best efforts, though. For example, my reader went on to say:

    If a teacher can come up with scenarios that actually ... require the benefits of one approach over the other, I suspect that all but the most stubborn would be quick to convert.

    In my years as a teacher, I've been repeatedly surprised by the fact that no, they won't. Some will change their majors. Others will cling to old ways at the cost of precious grade points, even in the face of repeated lack of success as a programmer. And, of course, those very best students will find a way to make it work using their existing skills, even at the cost of precious grade points. Really, though, why we penalize students very much for succeeding in a way we didn't anticipate?

    With the image of Professor Kingsfield firmly planted in my mind, I will think more about how the right project could help students by making change the only reasonable option. I could do worse than to be loved for having the wisdom of Kingsfield.

    And, as always, thanks to readers for their e-mail comments. They are an invaluable part of this blog for me!


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

    February 10, 2005 5:02 PM

    How's That Workin' For Ya?

    I recently saw a statement somewhere, maybe on the XP mailing list, to the effect that XP doesn't prevent people who will fail from failing; it helps people who will succeed to succeed more comfortably or more efficiently.

    I think that, in one sense, this is true. No software methodology can do magic. People who for whatever reason are unprepared to succeed are unlikely to succeed. And I believe that good developers can do even better when they work in an agile fashion.

    But in another sense I think that XP and the other agile methods can help developers get better at what they do. If a person makes a commitment to improve, then adopting XP's disciplines can become a better developer.

    This all came to the front of my mind yesterday as I read a short essay over at 43 Folders on systems for improving oneself. Merlin's comments on self-improvement systems caused a light bulb to go off: XP is a self-help system! Consider...

    • Successful self-help systems help a person to become more self-aware and to use what they observe to effect a more favorable solution.

    • Successful systems encourage simplicity and communication.

    Agile software methods draw on a desire to get better by paying attention to what the process and code tell us and then feeding that back into the system -- using what we learn to change how we do what we do.

    Practices such as continuous unit testing provide the feedback. The rhythm of the test-code-refactor cycle accentuates the salience of feedback, making it possible for the developer to make small improvements to the program over and over and over again. The agile methods also encourage using feedback from the process to fine-tune the process to the needs of the team, the client, and the project.

    Improvement doesn't happen by magic. The practices support acquiring information and feeding it back into the code.

    A person is more likely to stick with a system if it is simple enough to perform regularly and encourages small corrections.

    Merlin proposes that all successful self-improvement systems embody...

    ... a few basic and seemingly immutable principles:
    • action almost always trumps inaction
    • planning is crucial; even if you don't follow a given plan
    • things are easier to do when you understand why you're doing them
    • your brain likes it when you make things as simple as possible

    That sure sounds like an agile approach to software development. How about this:

    ... the idea basically stays the same: listen critically, reflect honestly, and be circumspect about choosing the parts that comport with your needs, values, and personal history. Above all, remember that the secret code isn't hiding ... -- the secret is to watch your progress and just keep putting one foot in front of the other. Keep remembering to think, and stay focused on achieving modest improvements in whatever you want to change. Small changes stick.

    Any software developer who wants to get better could do much worse than to adopt this mindset.


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

    February 09, 2005 11:10 AM

    Some Wednesday Potluck

    I've been so busy that writing for the blog has taken a back seat lately. But I have run across plenty of cool quotes and links recently, and some are begging to be shared.

    Why Be a Scientist?

    Jules Henri Poincare said...

    The scientist does not study nature because it is useful. He studies it because he delights in it, and he delights in it because it is beautiful.

    ... as quoted by Arthur Evans and Charles Bellamy in their book An Inordinate Fondness for Beetles.

    How to Get Better

    When asked what advice he would give young musicians, Pat Metheny said:

    I have one kind of stock response that I use, which I feel is really good. And it's "always be the worst guy in every band you're in." If you're the best guy there, you need to be in a different band. And I think that works for almost everything that's out there as well.

    I remember when I first learned this lesson as a high school chessplayer. Hang out with the best players you can find, and learn from them.

    (I ran across this at Chris Morris's cLabs wiki, which has some interesting stuff on software development. I'll have to read more!)

    All Change is Stressful

    Perryn Fowler reminds us:

    All change is stressful - even if we know it's good change. ...

    Those of us who attempt to act as agents of change, whether within other organisations or within our own, could do well to remember it.

    Perryn writes in the context of introducing agile software methods into organizations, but every educator should keep this in mind, too. We are also agents of change.


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

    February 04, 2005 1:30 PM

    Honey Rather Than Vinegar

    While reading about the muddled state of Groovy, I ran across a blog post on the topic of trying to get students to adopt new practices. Greg Wilson writes on his blog Pyre:

    It's easy to make students jump through hoops in a course. What's hard is convincing them that jumping through those hoops after the course is over really will make their lives better. The best way I've found so far is to bring in experienced programmers who are doing exciting things, and have them say, "Comments, version control, test-driven development..."

    Earlier in the same entry, he suggests that XP succeeds not because of its particular practices, but rather...

    ... that what really matters is deciding that you want to be a better programmer. If you make a sincere commitment to that, then exactly how you get there is a detail.

    That's spot on with what I said in my last message. Learning happens when a person opens himself to change. That openness makes it possible for the learner to make the commitment to a new behavior. With that commitment, even small changes in practice can grow to large changes in capability. And I certainly concur with Gregg's advice to bring in outsiders who are doing cool things. Some students reach a level of internal motivation in that way that they will never reach through being asked to change on their own.


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

    February 03, 2005 4:01 PM

    Small Differences Can Have a Large Effect

    The temperature here has risen to unseasonably high levels the last week or so. That means that I am able to run outdoors again. And I love it -- fresh air and open space are where the great running is. I live where the American Midwest meets its Great Plains, so by most folks' standard the land here is flat. But I live near a river, and we do have gently rising and falling terrain, which makes every run more interesting and more challenging than any track can offer.

    One thing I notice whenever I am able to break away from track running is an increase in the variability of my pace. When I run on a short indoor track, I usually find myself running relatively steady lap times, drawn into a rhythm by the short, repetitive environment.

    Another thing I notice is that tend to run faster than I'd like, even on days I'd rather take it easy. One good result of this is that I get faster, but the negative side effect is that I end up more tired all week long. That affects the other parts of my life, like my teaching and my time with my family.

    You might think that a couple of seconds per lap -- say, 52 second laps instead of 54 -- wouldn't make that much difference. That's less than 4%, right? But a small difference in effort can have a big effect of the body. That small difference compounds at every lap, much like interest in a bank account. What feels comfortable in the moment can be less so far after the fact, when that compounded difference makes itself apparent. There can value be in such stresses ("the only way to get faster is to run faster"), but there are also risks: a depressed immune system, increased susceptibility to injury, and the tiredness I mentioned earlier.

    Most runners learn early to respect small changes and to use them wisely. They learn to mix relatively easy runs and even off days in with their harder runs as a way to protect the body from overuse. Folks who train for a marathon are usually told never to increase their weekly mileage by more than 10% in a given week, and to drop back every second or third week in order to let the body adjust to endurance stress.

    At first, the 10% Rule seems like an inordinate restriction. "At this rate, it will take me forever to get ready for the marathon!" Well, not forever, but it will take a while. Most people don't have any real choice, though. The human body isn't tuned to accepting huge changes in endurance very quickly.

    But their is hope, in the bank account analogy above. You may have heard of the Rule of 72, an old heuristic from accounting that tells us roughly how quickly a balance can double. If a bank account draws 5% interest a year, then the balance will double in roughly 72/5 ~~ 14 years. At 10% interest, it will double in about seven. This is only a heuristic, but the estimates are pretty close to the real numbers.

    Applied to our running, the Rule of 72 reminds us that if we increase our mileage 10% a week, then we can double our mileage in only seven weeks! Throw in a couple of adjustment weeks, and still we can double in 10 weeks or less. And that's at a safe rate of increase that will feel comfortable to most people and protect their bodies from undue risks at the same time. Think about it: Even if you can only jog three miles at a time right now, you could be ready to finish a marathon in roughly 30 weeks! (Most training plans for beginners can get you there faster, so this is really just an upper bound...)

    What does this all have to do with software development? Well, I have been thinking about how to encourage students, especially those in my first-year course, to adopt new habits, such as test-driven design and refactoring. I had hoped that, by introducing these ideas early in their curriculum, they wouldn't be too set in their ways yet, with old habits too deeply ingrained yet. But even as second-semester programmers, many of them seem deeply wedded to how they program now. Of course, programmers and students are people, too, so they bring with them cognitive habits from other courses and other subjects, and these habits interact with new habits we'd like them to learn. (Think deeply about the problem. Write the entire program from scratch. Type it in. Compile it. Run it. Submit it. Repeat.)

    How can I help them adopt new practices? The XP mailing list discusses this problem all the time, with occasional new ideas and frequent reminders that people don't change easily. Keith Ray recently posted a short essay with links to some experience reports on incremental versus wholesale adoption of XP. I've been focusing on incremental change for the most part, due to the limits of my control over students' motivation and behavior.

    The 10% Rule is an incremental strategy. The Rule of 72 shows that such small changes can add up to large effects quickly.

    If students spends 10 minutes refactoring on the first day, and then add 10% each subsequent day, they could double their refactoring time in a week! Pretty soon, refactoring will feel natural, a part of the test-code-refactor rhythm, and they won't need to watch the clock any more.

    I'm not sure how to use this approach with testing. So far, I've just started with small exercises and made them a bit larger as time passed, so that the number of tests needed has grown slowly. But I know that many still write their tests after they think they are done with the assignment. I shouldn't complain -- at least they have tests now, whereas before they had none. And the tests support refactoring. But I'd like to help them see the value in writing the tests sooner, even first.

    Together, the 10% Rule and the Rule of 72 can result in big gains when the developer commits to a new practice in a disciplined way. Without commitment, change may well never happen. A runner who doesn't run enough miles, somehow increasing stamina and strength, isn't likely to make to the level of a marathon. That discipline is essential. The 10% Rule offers a safe and steady path forward, counting on the Rule of 72 to accumulate effects quicker than you might realize.


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

    January 28, 2005 4:43 PM

    Why Didn't I Know This Already?

    The little things I have left to learn... Twice today I encountered something about Java that I didn't know.

    First: a colleague had a piece of code with three variables typed as bytes:

    piecesRemaining = piecesAtStart - piecesTaken;

    The compiler complained about a loss of precision. When he cast the righthand side of the expression to byte, everything worked fine:

    piecesRemaining = (byte) (piecesAtStart - piecesTaken);

    So off I trudge to the Java Language Reference, where on Page 27 I find:

    Java performs all integer arithmetic using int or long operations. A value that is of type byte, short, or char is widened to an int or a long before the arithmetic operation is performed.

    So your RHS value are upcast to ints for the subtraction, resulting in a downcast on assignment. But why does Java work this way? Any ideas?

    Second: I'm teaching an undergraduate algorithms course this year for the first time in a long while, and I often find myself whipping up a quick program in Scheme or Java to demonstrate some algorithms we've designed in class. This afternoon I was implementing a brute-force algorithm for the old Gas Station Problem:

    A cyclic road contains n gas stations placed at various points along the route. Each station has some number of gallons of gas available. Some stations have more gas than necessary to get to the next station, but other stations do not have enough gas to get to the next station. However, the total amount of gas at the n stations is exactly enough to carry a car around the route exactly once.

    Your task: Find a station at which a driver can begin with an empty tank and drive all the way around the road without ever running out of gas.

    The input to your algorithm is a list of n integers, one for each station. The ith integer indicates the number of miles a car can travel on the gas available at the ith station.

    For simplicity, let's assume that stations are 10 miles apart. This means that the sum of the n integers will be exactly 10n.

    The output of your algorithm should be the index of the station at which the driver should begin.

    Our algorithm looked like this:

        for i ← 1 to n do
            tank ← 0
            for j ← i to ((i + n) mod n) do
                tank := tank + gas[j] - 10
                if tank < 0 then next i
            return i
    

    How to do that next i thing? I don't know. So off again I go to the language reference to learn about labels and the continue statement. Now, to be honest, I knew about both of these, but I had never used them together or even thought to do so. But it works:

        outer:
        for ( int i = 0; i < gas.length; i++ )
        {
            tank = 0;
            for ( int j = i; j < i + gas.length; j++ )
            {
                tank = tank + gas[j % gas.length] - 10;
                if ( tank < 0 )
                    continue outer;
            }
            return i;
         }
    

    Some days I have major epiphanies, but more often I learn some little nugget that fills an unexpected hole in the web of my knowledge. The Java gurus among you are probably thinking, "He really didn't know that? Sheesh..."

    Neither one of these Java nuggets is earth-shaking, just the sort of details I only learn when I need to use them in program for the first time. I suppose I could study the Java Language Reference in my free time, but I don't have the sort of job for which that sounds attractive. (Is there such a job?)


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

    January 28, 2005 9:49 AM

    Programming as Performance Art

    I've been following the development of Laurent Bossavit's software development dojo. He wrote about the idea in his blog a few times last year and then created a separate blog for it at this month at http://bossavit.com/dojo/.

    The most recent article there speculates about programming as a performance art. It seems that the guys in the dojo have been presenting their code to one another and doing some of the programming live in front of the group. The experience has caused the author to re-think his artistic sense of programming:

    Had I to choose earlier an art form which I felt connected to the act of programming, I would have picked book writing without hesitation. Something static, written at some time, read at another. Few dojo sessions later, I am not so positive anymore. I speculate the act of programming is also about the here and the now: how you currently live through the problem up to a satisfying conclusion, and how I feel engaged, watching your sharing techniques and insights. No cathartic experience so far -- hold your horses, this is sill embryonic stage -- although this could become a personal quest.

    I feel a kinship here after the first three week of my CS II class, in which my students and I have been "gang programming" Ron Jeffries's bowling game using TDD. I've spent very little time expounding ex cathedra; most of my remarks have been made in the flow of programming, with only an occasional impromptu mini-lecture of a few minutes. If you know me, you probably don't think of me as a natural performer, but I've felt myself slipping into the gentle drama of programming. New requirements puzzle us, then worry us. A test fails. Programming ideas compete for attention. Code grows and shrinks. Green bar. Relief.

    I hope that most of the students in the class are getting a sense of what it's like to make software. I also hope that they are enjoying the low drama of course.

    My recent experience has brought to mind my favorite article on this topic, Bill Wake's Programming as Performance Art. He tells of seeing a particularly stirring performance by Kent Beck and Jim Newkirk:

    They tackled the chestnut "Sieve of Eratosthenes." The 4-hand arrangement worked well, and let us see not only "programmer against complexity" but also "programmer against self" (when they started to make mistakes) and "programmer against programmer" (when they resolved their differences). The audience appreciated the show, but we should have applauded more enthusiastically.

    I don't know what I'd do if my students ever applauded. But even if they never do, I like the feel of our live programming sessions. We'll see how effective they are as learning episodes as the semester progresses.


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

    January 24, 2005 10:01 AM

    I Go To Extremes

    Brian Button recently posted a long blog entry on his extreme refactoring of the video store class from Martin Fowler's Refactoring. Brian "turned [his] refactoring knob up to about 12" to see what would happen. The result was extreme, indeed: no duplication, even in loops, and methods of one line only. He concluded, "I'm not sure that I would ever go this far in real life, but it is nice to know that I could."

    Turning the knobs up in this way is a great way to learn something new or to plumb for deeper understanding of something you already know. A few months ago, I wrote of a similar approach to deepening one's understanding off polymorphism and dynamic dispatch via a simple etude: Write a particular program with a budget of n if-statements or less, for some small value of n. As n approaches 0, most programmers -- especially folks for whom procedural thinking is still the first line of attack -- find this exercise increasingly challenging.

    Back at ChiliPLoP 2003, we had a neat discussion along these lines. We were working with some ideas from Karel the Robot, and someone suggested that certain if-statements are next to impossible to get rid of. For example, How can we avoid this if?

         public class RedFollowingRobot
         {
             public void move()
             {
                 if (nextSquare().isRed())
                     super.move();
             }
         }
    

    public class Square { public boolean isRed() { ... } }

    But it's possible... Joe Bergin suggested a solution using the Strategy pattern, and I offered a solution using simple dynamic dispatch. You can see our solutions at this wiki page. Like Brian said in his article, I'm not sure that I would ever go this far in real life, but it is nice to know that I could. This is the essence of the powerful Three Bears pattern: Often, in taking an idea too far, we learn best the bounds of its application.

    Joe and I like this idea so much that we are teaching a workshop based on it, called The Polymorphism Challenge (see #33 there) at SIGCSE next month. We hope that spending a few hours doing "extreme polymorphism" will help some CS educators solidify their OO thinking skills and get away from the procedural way of thinking that is for many of them the way they see all computational problems. If you have any procedural code that you think simply must use a bunch of if-statements, send it to me, and Joe and I will see if it makes a good exercise for our workshop!


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

    January 21, 2005 1:09 PM

    Get Ready for OOPSLA 2005

    Back in October, I signed on for a second year as program chair for the OOPSLA Educators Symposium. Last year's symposium went well, with Alan Kay's keynote setting an inspirational mood for the symposium and conference, and I welcomed the chance to help put together another useful symposium for OO eductaors. Besides, the chance to work with Ralph Johnson and Dick Gabriel on their vision for an evolving OOPSLA was too much to pass up.

    The calls for submissions to OOPSLA 2005 are available on-line now. All of the traditional options are available again, but what's really exciting are the new tracks: Essays, Lightning Talks, Software Studies, and FilmFest. Essays and Lightning Talks provide a new way to start serious conversations about programming, languages, systems, and applications, short of the academic research papers found in the usual technical program. I think the Software Studies track will open a new avenue in the empirical study of programs and their design. Check these CFPs out.

    Of course, I strongly encourage all of you folks who teach OOP to consider submitting a paper, panel proposal, or nifty assignment to the Educators Symposium. As much as software development, teaching well depends on folks sharing successful techniques, results of experiments, and patterns of instructional materials.

    This year, the symposium is honored to have Ward Cunningham as our keynote speaker. As reported here, Ward spoke at last year's OOPSLA. I love Ward's approach to programming, people, and tools. "OOPSLA is about programming on the edge, doing practical things better than most." "Be receptive to discovery." The symposium's program committee is looking forward to Ward sharing his perspective with educators.

    If you've been to OOPSLA before, you know how valuable this conference can be to your professinal development. If not, ask someone who has been, or trust me and try it yourself. You won't be disappointed.


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

    January 17, 2005 9:19 AM

    Csikszentmihalyi to Visit UNI

    I recently learned that Mihaly Csikszentmihalyi will be visit my campus for several talks in early March. Csikszentmihalyi (whose name is pronounced 'me-HI chick-SENT-me-hi') is well known for his theory of flow and its role in creativity and learning. Long ago I read some of Csikszentmihalyi's work, though I've never read the bestseller that made his name, Flow: The Psychology of Optimal Experience. Maybe now is the time.

    Throughout his career, Csikszentmihalyi has studied the psychology of the creative individual: What characteristics are common to creative individual? How do creative people create? His talks here, though, will focus on the context in which creative individuals thrive. His main talk will describe how to create the sort of environment that must exist in order for a creative individual to contribute most effectively. His other talks will focus on specific contexts: How can educators "design curricula that capitalize on the human need to experience flow?" How work can contribute to well-being, and how can managers and employees create the right sort of workplace?

    We agile folks often speak of "rhythm" and how TDD and refactoring can create a highly productive flow. And, while I've often heard critics say that P limits the individuality of developers, I've always thought that agile methods can unleash creativity. I'm curious to hear what Csikszentmihalyi has to say about flow and how we can create environments that support and nurture it, both for software development and for learning. You may recall an earlier discussion here about flow in learning, inspired by the Suzuki method of instruction and by Alan Kay's talks at OOPSLA. I think Csikszentmihalyi can help me to understand these ideas better.


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

    January 14, 2005 4:07 PM

    Bowling for CS II

    I took a leap of faith this week.

    I teach our second course, CS II. It comes between an intro course in which students learn a little bit about Java and a little bit about objects, and a traditional data structures course using Ada95. The purpose of CS II is to give students a deeper grounding in Java and object-oriented programming.

    The first thing I did on our first day of class was to write code. The first line of code I wrote was a test. The next thing I did was try to compile it, which failed, so I wrote the code to make it compile. Then I ran the test in JUnit and watched it fail. Then we wrote the code to make it pass.

    And then we did it again, and again, and again.

    I've long emphasized various agile practices in my courses, even as early as CS II, especially short iterations and refactoring. In recent semesters I've encouraged it more and more. Soon after fall semester ended, I decided to cross the rubicon, so to speak. Let tests drive all of our code. Let students feel agile development from all class and lab work.

    Day 1 went well. We "gang-programmed", with students helping me to order requirements, write tests, find typos, and think through application logic. The students responded well to the unexpected overhead of JUnit. Coming out of the first course, they aren't used to non-java.* or extra "stuff".

    In our second session, a lab class, students installed JUnit in their own accounts and wrote their first Java code of the semester: a JUnit test against the app we built in Day 1.

    Oh, the app? Ron Jeffries' BowlingGame etude. It had just enough complexity to challenge students but not enough to pull too much of their attention away from the strange and wonderful new way we were building the program.

    Next time, we'll add a couple of requirements that lead us to factor out a Frame, allowing us to see refactoring and how tests support changing their code.

    I'm excited even as I'm a little on edge. New things in the classroom do that to me.


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

    January 06, 2005 3:03 PM

    Looking Under the Hood to Be a Better Programmer

    Brian Marick just blogged on Joel Spolsky's Advice for Computer Science College Students. I had the beginnings of an entry on Joel's stuff sitting in my "to blog" folder, but was planning to put it off until another day. (Hey, this is the last Thursday I'll be able to go home early for sixteen weeks...) But now I feel like saying something.

    Brian's entry points that Joel's advice reflects a change in the world of programming from back when we old fogies studied computer science in school: C now counts as close enough to the hardware to be where students should learn how to write efficient programs. (Brian has more to say. Read it.)

    I began to think again about Joel's advice when I read the article linked above, but it wasn't the first time I'd thought about it. In fact, I had a strong sense of deja vu. I looked back and found another article by Joel, on leaky abstractions, and then another, called Back to Basics. There is is a long-term theme running through Joel's articles, that programmers must understand both the abstractions they deal in and how these abstractions are implemented. In some ways, his repeated references to C are mostly pragmatic; C is the lingua franca at the lowest level of software development, even -- Brian mentions -- for those of us who prefer to traffic in Ruby, Smalltalk, Perl or Python. But C isn't the key idea Joel is making. I think that this, from the leaky abstractions, article, is [emphasis added]:

    The law of leaky abstractions means that whenever somebody comes up with a wizzy new ... tool that is supposed to make us all ever-so-efficient, you hear a lot of people saying "learn how to do it manually first, then use the wizzy tool to save time." [...] tools which pretend to abstract out something, like all abstractions, leak, and the only way to deal with the leaks competently is to learn about how the abstractions work and what they are abstracting. So the abstractions save us time working, but they don't save us time learning.

    And all this means that paradoxically, even as we have higher and higher level programming tools with better and better abstractions, becoming a proficient programmer is getting harder and harder.

    Programming has always been hard, but it gets harder when we move up a level in abstraction, because now we have to worry about the interactions between the levels. Joel's article argues us that it's impossible to create an abstraction that doesn't leak. I'm not sure I willing to believe it's impossible just yet, but I do believe that it's close enough for us to act as if it is.

    That said, Brian's history lesson offers some hope that that the difficulty of programming isn't growing harder at an increasing rate, because sometimes what counts as the lowest level rises. C compilers really are good enough these days that we don't have to learn assembly in order to appreciate what's happening at the machine level. Or do we?

    Oh, and I second Brian's recommendation to read Joel's Advice for Computer Science College Students. He may just be one of those old fogies "apt to say goofy, antediluvian things", but I think he's spot on with his seven suggestions (even though I think a few of his reasons are goofy). And that includes the one about microeconomics!


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

    January 05, 2005 2:36 PM

    Trust and the Tyranny of Choice

    When I'm out shopping for any big-ticket item, such as a car, I am notoriously slow to pull the trigger. I can be just as slow on even relatively inexpensive items like stereos, or snack food. My wife long ago learned to give me time, to walk off and let me stew a bit, before putting any pressure on me to make a decision. But she also learned that without such pressure I may never decide to buy or not. Talk about the Halting Problem.

    What's the cause of my shopping behavior? Perhaps I'm prone to regret and am trying to protect myself from that gnawing feeling that I've made the wrong choice. Having even a few alternatives makes my choice difficult. (To be honest, I think I worry about feeling regret at having spent the money at all, which just makes me cheap. :-)

    Difficulty making choices has been a thread over on the XP discussion list recently. Jason Yip read Barry Schwartz's April 2004 Scientific American article The Tyranny of Choice, which is based on his popular book The Paradox of Choice. Schwartz argues that there exists something of a Laffer curve at work when it comes to the psychology of decision making. Having few or no choices gives people little opportunity to control their destinies, which often results in being disappointed with how things turn out. Having many choices gives people a feeling of control but increases the probability of making the wrong choice, which leads to regret. Schwartz points out that regret tends to make people more unhappy than disappointment. From this, he concludes that having too many alternatives is actually worse for people than having too few.

    Jason raised Schwartz's thesis in the context of customer choice in XP, brought on by an earlier thread about optional scope contracts. He asked if anyone had observed the "tyranny of choice" phenomenon manifest itself as resistance to more flexible approaches to defining project scope. We can frame the question even more broadly, as XP offers many choices in the release and iteration planning phases of a project that customers may not be used to. The resulting thread of discussion offered several interesting takes on this idea. Check it out.

    When I'm doing XP, my customers face a somewhat different situation than I do when I'm buying a car. Customers tend to make their choices as part of a longer-term relationship, and the new choices P gives them are more about ordering the steps of the project than selecting only one from a set of alternatives. If they make a choice they regret, they will have a chance to re-prioritize requirements when helping to plan the next release. As a result, their regret will tend to be short-lived and more about short-term opportunity cost. (Mike Feathers made a similar argument on the discussion list.)

    Of course, when developing software in a more traditional way, someone is making all these choices, though often it is the technical team. You'd think that customers would be no worse off making their own choices, even if they come to regret them, than by having some programmer make the decision in his cubicle one night. But that's the vexing part of Schwartz's thesis: They feel worse off in regret at their decision than they do in disappointment at the programmer's.

    Knowing this, agile developers can play a valid role in helping their customers make choices. When they see a customer having difficulty setting priorities, they can inject some of their professional experience into the mix. Telling customers how past projects have gone may help them set a priority for the current release. Reminding them that they will have a chance to guide the project's course again at the next release or iteration may help them avoid paralysis motivated by fear of regret.

    Some folks on the XP list offered some fun little strategies for helping break a deadlock in decision making. For example, if the customer says that all features are equally important, try selecting what seems to you to be the least valuable feature as the first one to implement. Sometimes, that's enough of a push to get the customer to think he can do a better job than you and so choose. I'm guessing that it's especially important to manage expectations in this scenario -- you don't want the customer to think you tricked him into making a choice he ultimately regrets, because then he'll be saddled not only with regret but also a distrust of you. And trust is essential to a good working relationship, especially in an agile approach.

    For me, this brings to mind my younger daughter. Since she was a toddler, she has generally had trouble deciding, whether the choice is among alternatives for dessert, or outfits to where, or whether to ride home in the car with mommy or daddy. (Like many other families, we often end up in the same with both cars!) Instinctively, I've always tried to reassure her that her decision isn't the Final Answer, that if she later wishes she'd chosen ice cream for dessert, well then, we can just have ice cream tomorrow. That hasn't always seemed to help, at least not with the choice at hand. But I think that it's a good way to approach the situation: don't put undue pressure on her, and help calm her fears -- whether of regret or of disappointing me, which sometimes seems to be a factor in her decisions that I didn't expect. Building a relationship in which she can trust me is the best I can hope for in helping her learn to choose. And, as she's gotten older, she has become a more confident decision maker.

    Back to software: Ultimately, I think that the "paradox of choice" phenomenon is more a case for agile methods than a case against them. It underscores one of the great strengths of the agile approaches: an attitude toward job and customer based in respect, trust, and communication. When we value these ahead of hard-and-fast rules and ahead of "the process", we are able to adjust our approach to the particulars of the customer and the current project.


    Posted by Eugene Wallingford | Permalink | Categories: Software Development

    December 27, 2004 11:19 AM

    Dispatches from the Programmer Liberation Front

    Owen Astrachan pointed me in the direction of Jonathan Edward's new blog. I first encountered Edwards's work at OOPSLA 2004, where he gave a talk in the Onward! track on his example-driven programming tool.

    In his initial blog entries, Edwards introduces readers to the programming revolution in which he would like to participate, away from more powerful and more elegant languages and toward a programming for the Everyman, where we build tools and models that fit the way the real programmer's mind works. His Onward! talk demoed a initial attempt at a tool of the sort, in which the programmer gives examples of the desired computation and the examples become the program.

    Edwards's current position stands in stark contrast to his earlier views as a more traditional researcher in programming languages. As many of us are coming to see, though, "programming is about learning to work effectively in the face of overwhelming complexity" than it is about ever more clever programming languages and compiler tricks. When it comes to taming the complexity inherent in large software, "simplicity, flexibility, and usability are more effective than cleverness and elegance."

    The recent trend toward agile development methodologies and programming support tools such as JUnit and Eclipse also draw their inspiration from a desire for simpler and more flexible programs. Most programmers -- and for Edwards, this includes even the brightest -- don't work very well with abstractions. We have to spend a lot of brain power managing the models we have of our software, models that range from execution on a standard von Neumann architecture up to the most abstract designs our languages will allow. Agile methods such as XP aim to keep programmers' minds on the concrete embodiment of a program, with a focus on building supple code that adapts to changes in our understanding of the problem as we code. Edwards even uses one of Kent Beck's old metaphors that is now fundamental to the agile mindset: Listen carefully to what our code is telling us.

    But agile methods don't go quite as far as Edwards seems to encourage. They don't preclude the use of abstract language mechanisms such as closures or higher-order procedures, or the use of a language such as Haskell, with its "excessive mathematical abstraction". I can certainly use agile methods when programming in Lisp or Smalltalk or even Haskell, and in those languages closures and higher-order procedures and type inference would be natural linguistic constructs to use. I don't think that Edwards is saying such things are in and of themselves bad, but only that they are a symptom of a mindset prone to drowning programmers in the sort of abstractions that distract them from what they really need in order to address complexity. Abstraction is a siren to programmers, especially to us academic types, and one that is ultimately ill-suited as a universal tool for tackling complexity. Richard Gabriel told us that years ago in Patterns of Software (pdf).

    I am sympathetic to Edwards's goals and rationale. And, while I may well be the sort of person he could recruit into the revolution, I'm still in the midst of my own evolution from language maven to tool maven. Oliver Steele coined those terms, as near as a I can tell, in his article The IDE Divide. Like many academics, I've always been prone to learn yet another cool language rather than "go deep" with a tool like emacs or Eclipse. But then it's been a long time since slogging code was my full-time job, when using a relatively fixed base of language to construct a large body of software was my primary concern. I still love to learn a Scheme or a Haskell or a Ruby or a Groovy (or maybe Steele's own Laszlo) to see what new elegant ideas I can find there. Usually I then look to see how those ideas can inform my programming in the language where I do most of my work, these days Java, or in the courses where I do most of my work.

    I don't know where I'll ultimately end up on the continuum between language and tool mavens, though I think the shift I've been undergoing for the last few years has taken me to an interesting place and I don't think I'm done yet. A year spent in the trenches might have a big effect on me.

    As I read Edwards's stuff, and re-read Steele's, a few other thoughts struck me:

    • In his piece on the future of programming, Edwards says,

      I retain a romantic belief in the potential of scientific revolution ... that there is a "Calculus of Programming" waiting to be discovered, which will ... revolutionize the way we program....

      (The analogy is to the invention of the calculus, which revolutionized the discipline of physics.) I share this romantic view, though my thoughts have been with the idea of a pattern language of programs. This is a different sort of 'language' than Edwards means when he speaks of a calculus of programs, but both types of language would provide a new vocabulary for talking about -- and building -- software.

    • Later in the same piece, Edwards says,

      Copy & paste is ubiquitous, despite universal condemnation. ... I propose to decriminalize copy & paste, and even to elevate it into the central mechanism of programming.

      Contrary to standard pedagogy, I tell my students that it's okay to copy and paste. Indeed, I encourage it -- so long as they take the time after "making it work" to make it right. This means refactoring to eliminate duplication, among other things. Some students find this to be heresy, or nearly so, which speaks to how well some of their previous programming instructors have drilled this wonderful little practice out of them. Others take to the notion quite nicely but, under the time pressures that school creates for them and that their own programming practices exacerbate, have a hard time devoting sufficient energy to the refactoring part of the process. The result is just what makes copy and paste so dangerous: a big ball of mud with all sorts of duplicated code.

      Certainly, copy and paste is a central mechanism of doing the simplest thing that could possibly work. The agile methods generally suggest that we then look for ways to eliminate duplication. Perhaps Edwards would suggest that we look for ways to leave the new code as our next example.

    • At the end of the same piece, Edwards proposes an idea I've never seen before: the establishment of "something like a teaching hospital" in which to develop this new way of programming. What a marvelous analogy!

      Back when I was a freshman architecture major, I saw more advanced students go out on charrette. This exercise had the class go on site, say, a road trip to a small town, to work as a group to design a solution to a problem facing the folks there, say, a new public activity center, under the supervision of their instructors, who were themselves licensed architects. Charrette was a way for students to gain experience working on a real problem for real clients, who might then use the solution in lieu of paying a professional firm for a solution that wasn't likely to be a whole lot better.

      Software engineering courses often play a similar role in undergraduate computer science programs. But they usually miss out on a couple of features of a charrette, not the least of which is the context provided by going to the client site and immersing the team in the problem.

      A software institute that worked like a teaching hospital could provide a more authentic experience for students and researchers exploring new ways to build software. Clients would come to the institute, rather than instructors drumming up projects that are often created (or simplified) for students. Clients would pay for the software and use it, meaning that the product would actually have to work and be usable by real people. Students would work with researchers and teachers -- who should be the same people! -- in a model more like apprenticeship than anything our typical courses can offer.

      The Software Engineering Institute at Carnegie Mellon may have some programs that work like this, but it's an idea that is broader than the SEI's view of software engineering, one that could put our CS programs in much closer touch with the world of software than many are right now.

    There seems to be a wealth of revolutionary projects swirling in the computer science world these days: test-driven development, agile software methods, Croquet and eToys .... That's not all that unusual, but perhaps unique to our time is the confluence of so many of these movements in the notion of simplicity, of pulling back from abstraction toward the more concrete expression of computational ideas. This more general trend is perhaps a clue for us all, and especially for educators. One irony of this "back to simplicity" trend is that it is predicated on increasingly complex tools such as Eclipse and Croquet, tools that manage complexity for us so that we can focus our limited powers on the things that matter most to us.


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

    December 22, 2004 10:19 AM

    Why We Choke Under Pressure

    In two recent articles (here and here), I participated in a conversation with John Mitchell and Erik Meade about the role of speed in developing software development skills. While the three of us agreed and disagreed in some measure, we all seemed to agree that "getting faster" is a valuable part of the early learning process.

    Now comes an article from cognitive psychologists that may help us understand better the role of pressure. My old cognitive psychology professor, Tom Carr, and one of his students, Sian Bielock, have written an article, "Why High Powered People Fail: Working Memory and 'Choking Under Pressure' in Math", to appear in the journal Psychological Science. This article reports that strong students may respond worse under the pressure of hard exams than less gifted students. This form of choking seems to result from pressure-induced impairment of working memory, which is one of the primary advantages that stronger students have over others. You can read a short article from the NY Times on the study, or a pre-print of the journal article for full details.

    The new study is a continuation of Beilock's doctoral research, which seems to have drawn a lot of interest in the sports psychology world. An earlier study by Beilock and Carr, On the Fragility of Skilled Performance: What Governs Choking Under Pressure? from the Journal of Experimental Psychology: General supports the popular notion that conscious attention to internalized skills hurts performance. Apparently, putting pressure on a strong student increases their self-consciousness about their performance, thus leading to what we armchair quarterbacks call choking.

    I'm going to study these articles to see what they might teach me about how not to evaluate students. I am somewhat notorious among my students for having difficult tests, in both content and length. I've always thought that the challenge of a tough exam was a good way for students to find out how far they've advanced their understanding -- especially the stronger students. But I s I need to be careful that my exams not become tests primarily of handling pressure well and only secondarily about understanding course content.

    By the way, Tom Carr was one of my all-time favorite profs. I enjoyed his graduate course in cognitive psychology as much as any course I ever took. He taught me a lot about the human mind, but more importantly about how a scientist goes about the business of trying to understand it better. I still have the short papers I wrote for that course on disk (the virtues of plaintext and nroff!). I was glad to see some of his new work.


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

    December 18, 2004 1:59 PM

    Fowler on Metaphor

    Martin Fowler has a dandy blog entry on the good and the bad of playing the "metaphor game" with software development. This was the take-home point for me:

    ... it all comes down to how you use the metaphor. Comparing to another activity is useful if it helps you formulate questions; it's dangerous when you use it to justify answers.

    I've always had an uneasy relationship with metaphors for software development, though I'm a sucker for the new ones I run across. But what do I gain from the metaphors, and how do I avoid being burned by them? Martin's article captures it.

    Maybe this is something I should have known along. But I didn't. Thanks, Martin.


    Posted by Eugene Wallingford | Permalink | Categories: Software Development

    December 15, 2004 10:46 AM

    Kent Beck on Developer Testing and System Health

    Kent Beck

    While my students are taking their object-oriented programming final exam, I'm listening to Kent Beck's talk on developer testing at the recent Developer Testing Forum held at PARC. The big theme of the talk is that developer testing is a way that an individual programmer can take control of his own accountability -- whether or not he adopts other agile practices, whether or not anyone else in his organization goes agile. Kent's been talking a lot about accountability lately, and I think it captures one of those very human values that underlie the agile methods, one of the non-techie reasons that I am drawn to the agile community.

    My favorite idea in the talk is one that Kent introduces right away: the distinction between quality (an instantaneous measure of a system's goodness) and health (a measure over time). I'm not sure I like the use of "quality" to mean an instantaneous measure, but I love the distinction. Many developers, including students, mistake "there are no bugs in my code" with "this is good code". In one sense, I suppose this is true. The code runs. It performs as desired. That is a Good Thing.

    But in another sense the implication is just wrong. Can people extend the program? Change it? Use it? Port it? Kent's turns to his health metaphor to explain. In my words: A person may have a good heart rate and normal blood pressure, but if he can't walk around the block without keeling over then he's probably not all that healthy.

    Refactoring mercilessly is a practice that recognizes the importance of the distinction between quality and health. Just because my code passes all the tests does not mean that the code is healthy. At least it's not as healthy as it can be. Refactoring is an exercise regimen for my system. It seeks to improve the long-term health of my program by drawing on its strength at the moment.

    Rigorous developer testing also recognizes the importance of this distinction. Having tests means that I can extend and change my code -- work akin to walking around the block -- with some confidence that I won't break the system. And, if I do, the system helps me recover from any errors I introduce. The tests are the immune system of my program!

    I really like this "system health" metaphor and think it extends quite nicely to many of the principles and practices of the agile methods. Continuous feedback and sustainable pace spring to mind immediately. Others, such as continuous integration and pair programming, require some thought. That will make for a future blog entry!

    Oh, and one other thing I liked from the talk... In the Q-n-A session after the talk, someone asked Kent how we know that our tests are correct. They are, after all, software, too. Kent said that you can't ever know for certain, but you can be more or less confident, depending on how thoroughly you test and refactor. It's like cross-checking sums in arithmetic or accounting. Over the long run, the chance that you make the offsetting mistakes in the code and the tests He made an analogy to mathematical proof, saying something to this effect:

    There's no such thing as proof in software. Proof of correctness isn't proof of correctness; it's proof of equivalence. "Here is one expression of what I'm trying to compute, and here's another expression of what I'm trying to compute, and they match." That's what you do with a proof of correctness. Tests and code are the same way. You're saying these two expressions are equivalent in some sense. ... That means my confidence in the answer is much, much higher.

    Well said. Scientific reasoning, even in the artificial world of mathematics, is about confidence, not certainty; evidence, not proof. We should not expect more of the messy, human enterprise of building software.

    (I have written about tests and proofs before, and of course there is the wonderful Donald Knuth quote in Alan Kay's talks at OOPSLA.)


    Posted by Eugene Wallingford | Permalink | Categories: Software Development

    December 14, 2004 9:16 AM

    Programming a lá Hoffman or Olivier

    As I write final exams and begin to think ahead to next semester, I've been thinking about how I teach programming and software development. Sometimes, I get so busy with all of the extras that can make programming interesting and challenging and more "real-world" -- objects and design and refactoring and GUIs and unit tests and frameworks and ... -- that I lose sight of the fact that my students are just trying to learn to write programs. When the abstractions and extra practices get in the way of learning, they have become counterproductive.

    I'd like to streamline my approach to programming courses a bit. First, I'll make some choices about which extras are more distraction than contribution, and eliminate them. Second, I'll make a conscious effort to introduce abstractions when students can best appreciate them: after having concrete experience with problems and techniques for solving them.

    My colleagues and students need not fear that I am going back to the Dark Ages with my teaching style. My friend Stuart Reges (more information at his old web page) isn't going quite that far, but he is in the process of redesigning his introductory courses on the model of his mid-1980s approach. He seems to be motivated by similar feelings, that many of the ideas we've added to our intro courses in the last 20 years have gotten in the way of teaching programming. Where Stuart and I differ is that I don't think there is anything more "fundamental" about what we did in Pascal in the '80s than what we should do with objects and messages in, say, Java. The vocabulary and mindset are simply different. We just haven't quite figured out the best way to teach programming in the new mindset.

    I wish Stuart well in his course design and hope to learn again from what he does. But I want to find the right balance between the old stuff -- what my colleagues call "just writing programs" -- and the important new ideas that can make us better programmers. For me, the first step is a renewed commitment to having students write programs to solve problems before having them talking about writing programs.

    This train of thought was set off by a quote I read over at 43 Folders. The article is about "hacking your way out of writer's block" but, as with much advice about writing, it applies at some level to programming. After offering a few gimmicks, the writer says:

    On the other hand, remember Laurence Olivier.

    One day on the set of Marathon Man, Dustin Hoffman showed up looking like shit. Totally exhausted and practically delirious. Asked what the problem was, Hoffman said that at this point in the movie, his character will have been awake for 24 hours, so he wanted to make sure that he had been, too. Laurence Olivier shook his head and said, "Oh, Dusty, why don't you just try acting?"

    I don't want all the extras that I care about -- and that I want students to care about -- to be affectations. I don't want to be Dustin Hoffman to Stuart's Olivier. Actually that's not quite true... I admire Hoffman's work, have always thought him to be among the handful of best actors in Hollywood. I just don't want my ideas to become merely affectations, to be distractions to students as they learn the challenging and wonderful skill of programming. If I am to be a method teacher, I want the method to contribute to the goal. Ultimately, I want to be as comfortable in what I'm doing in the classroom as Hoffman is with his approach to acting. (Though who could blame him if he felt a little less cocksure when chided by the great Olivier that day?)

    The bottom line for now is that there are times when my students and I should just write programs. Programs that solve real problems. Programs that work. We can worry about the abstract stuff after.


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

    December 07, 2004 3:57 PM

    An Agile Lesson from David Parnas

    Yesterday, someone reminded me of my friend Rich Pattis's Quotations for Learning Programming. I jumped, randomly as near as I can tell, to the Os and had not scanned too far down the page when I saw this quote:

    As a rule, software systems do not work well until they have been used, and have failed repeatedly, in real applications.

    - D. Parnas

    Of course, David Parnas is a famous computer scientist, well known for his work on modularity and software design. Many give him credit for best explaining encapsulation as a design technique. He is revered as an icon of traditional software engineering.

    Yet, when I read this quote, I could help but think, "Maybe Parnas is a closet agile developer." :-) Frequent readers may recall that I do this occasionally... See my discussion of Dijkstra as a test-driven developer.

    Whether Parnas is sympathetic to the methodological side of agile software development or not, this quote points out a truth of software development that is central to agile approaches: There is benefit in getting to working code sooner. The motive usually given for this is so that developers can learn about the problem and the domain from writing the code. But perhaps a secondary value is that it can begin to fail sooner -- but in the lab, under test-driven conditions, where developers can learn from those *failures* and begin to fix them sooner.

    I have to be careful not to misinterpret a person's position by projecting my own views onto a single quote taken out of context. For example, I can surely find a Parnas quote that could easily be interpreted as condemning agile software methodologies (in particular, I'm guessing, their emphasis on not doing big design up front).

    I don't worry about such contradictions; I prefer to use them as learning opportunities. When I see a quote like the one above, I like to take a moment to think... Under what conditions can this be right? When does it fail, or not hold? What can I learn from this idea that will make me a better programmer or developer? I don't think I'd ever consciously considered the idea that continuous feedback in XP might be consist of the same sort of failure that occurs when we deploy a live system. Parnas quote has me thinking about it now, and I think that I may learn something as a result.

    More subconsciously agile quotes?

    As I scanned Rich's list in my agile state of mind, a few others caught my eye...

    • Blaise Pascal, proponent of refactoring?

      I have made this letter longer than usual, only because I have not had the time to make it shorter.

    • An anonymous cautionary tale about agile methods -- but also about traditional software engineering?

      The fast approach to software development: Ready, fire, aim (the fast approach to software development).
      The slow approach to software development: Ready, aim, aim, aim, aim ...

    • Maybe those guys in Redmond know something about agility after all...

      Microsoft, where quality is job 1.1.

    • Finally, this quote has long been a favorite of mine. I have it hanging on the wall in my home office:

      We are what we repeatedly do.
      Excellence, then, is not an act, but a habit.

      - Aristotle

    This quote isn't a statement about agile practice, or even more generally about pragmatic practice. It is a hallmark of the reflective professional. It's also a pretty good guide for living life.


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

    December 07, 2004 6:24 AM

    More on Software Speed Training

    Last evening, I commented on the idea of speed training for software developers, raised in Erik Meade's blog. John Mitchell also commented on this idea. Check out what John has to say. I think he makes a useful distinction between pace and rhythm. You'll hear lots of folks these days talk about rhythm in software development; much of the value of test-driven development and refactoring lie in the productive rhythm they support. John points out that speed work isn't a good idea for developers, because that sort of stress doesn't work in the same way that physical stress works on the muscles. He leaves open the value of intensity in learning situations, more like speed play, which I think is where the idea of software fartleks can be most valuable.

    Be sure to check out the comments to John's article, too. There, he and Erik hash out the differences between their positions. Seeing that comment thread make me again want to add comments to my blog again!


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

    December 06, 2004 6:57 PM

    Speed Training for Software Developers

    In making analogies between software development and running, I've occasionally commented on sustainable pace, the notion from XP that teams should work at a pace they can sustain over time rather than at breakneck paces that lead to bad software and burn-out. In one entry, I discuss the value of continuous feedback in monitoring pace. In another, I describe what can happen when one doesn't maintain a sustainable pace, in the short tem and over the longer term.

    Not unexpectedly, I'm not alone in this analogy. Erik Meade recently blogged on sustainable pace and business practice. I was initially drawn to his article by its title reference to increasing your sustainable pace via the fartlek. While I liked his use of the analogy to comment on standard business practice, I was surprised that he didn't delve deeper into the title's idea.

    Fartlek is Swedish for "speed play" and refers to an unstructured way for increasing one's speed while running: occasionally speed up and run faster for a while, then slow down and recover. We can contrast this approach to more structured speed work-outs such as Yasso 800s, which specify speeds and durations for fast intervals and recoveries. In a fartlek, one simply has fun speeding up and slowing down. This works especially well when working out with a friend or friends, because partners can take turns choosing distances and speeds and rewards. In the case of both fartleks and structured interval training, though, the idea is the same: By running faster, you can train your body to run faster better.

    Can this work for software development? Can we train ourselves to develop software faster better?

    It is certainly the case that we can learn to work faster with practice when at the stage of internalizing knowledge. I encourage students to work on their speed in in-class exercises, as a way to prepare for the time constraints of exams. If you are in the habit of working leisurely on every programming task you face, then an exam of ten problems in seventy-five minutes can seem like a marathon. By practicing -- solving lots of problems, and trying to solve them quickly -- students can improve their speed. This works because the practice helps them to internalize facts and skills. You don't want forever to be in the position of having to look up in the Java documentation whether Vectors respond to length() or size().

    I sometimes wonder whether working faster actually helps students get faster or not, but even if it doesn't I am certain that it helps them assess how well they've internalized basic facts and standard tasks.

    But fartleks for a software development team? Again, working on speed may well help teams that are at the beginning of their learning curves: learning to pair program, learning to program test-first, learning to use JUnit, ... All benefit from lots of practice, and I do believe that trying to work efficiently, rather than lollygagging as if time were free, is a great way to internalize knowledge and practice. I see the results in the teams that make up my agile software development course this semester. The teams that worked with the intention of getting better, of attempting to master agile practices in good faith, became more skilled developers. The teams that treated project assignments as mostly a hurdle to surmount still struggle with tools and practices. But how much could speed work have helped them?

    The bigger question in my mind involves mature development teams. Will occasional speed workouts, whether from deadline pressure on live jobs or on contrived exercises in the studio, help a team perform faster the next time they face time pressure? I'm unsure. I'd love to hear what you think.

    If it does work, we agile developers have a not-so-secret advantage... Pair programming is like always training with a friend!

    When a runner prefers to run alone rather than with others, she can still do a structured work-out (your stopwatch is your friend) or even run fartleks. Running alone leaves the whole motivational burden on the solo runner's shoulders, but the self-motivated can succeed. I have run nearly every training run the last two years alone, more out of circumstance than preference. (I run early in the morning and, at least when beginning, was unsuitable as a training partner for just about any runner I knew.) I can remember only two group runs: a 7-miler with two faster friends about two weeks before my first marathon last fall, and an 8-mile track workout the day before Thanksgiving two weeks ago. As for the latter, I *know* that I trained better and harder with a friend at my side, because I lacked the mental drive to go all out alone that morning.

    Now I'm wondering about how pair programming might play this motivational role sometimes when writing software. But that blog entry will have to wait until another day.


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

    December 06, 2004 8:14 AM

    Learning via the Blogosphere

    This is why I love the blogosphere so much. Somehow, I stumble across a link to Leonardo, an open-source blogging and wiki engine written in Python. I follow the link and start reading the blog of Leonardo's author, James Tauber. It's a well-written and thoughtful set of articles on an interesting mix of topics, including Python, extreme programming, mathematics, linguistics, New Testament Greek, music theory and composition, record producing and engineering, filmmaking, and general relativity. For example, my reading there has taught me some of the mathematics that underlie recent work on proving the Poincare Conjecture.

    But the topic that attracted my greatest attention is the confluence of personal information management, digital lifestyle aggregation, wiki, blogging, comments and trackbacks, and information hosting. I've only recently begun to learn more deeply about the issue of aggregation and its role in information sharing. This blog argues for an especially tight intellectual connection among all of these technologies and cultures. For example, Tauber argues that wiki entries are essentially the same as blog trackbacks, and that trackbacks could be used to share information about software projects among bosses and teammates, using RSS feeds, and to integrate requests with one's PIM. But I'm not limited to reading Tauber's ideas, as he links to other blogs and web pages that present alternative viewpoints on this topic.

    Following all these threads will take time, but that I can at all is a tribute to the blogosphere. Certainly, all of this could have been done in the olden days of the web, and indeed many people were publishing there diverse ideas about diverse topics back then. But the advent of RSS feeds and blogging software and wikis has made the conversation much richer, with more power in the hands of both readers and writers. Furthermore, the blogging culture encourages folks to prepare their ideas sooner for public consumption, to link ideas in a way that enables scientific inquiry, to begin a conversation rather than just publish a tract.

    The world of ideas is alive and well.


    Posted by Eugene Wallingford | Permalink | Categories: General, Software Development

    December 03, 2004 10:11 AM

    The Theory of Patches

    Recently, I ran across an interesting article by David Roundy called The Theory of Patches, which is actually part of the manual for Darcs, a version-control alternative to CVS and the like. Darcs uses an inductive definition to define the state of a software artifact in the repository:

    So how does one define a tree, or the context of a patch? The simplest way to define a tree is as the result of a series of patches applied to the empty tree. Thus, the context of a patch consists of the set of patches that precede it.

    Starting with this definition, Roundy goes on to develop a set of light theorems about patches, their composition, and their merging. Apparently these theorems guide the design and implementation of Darcs. (I haven't read that far.)

    The reason I found this interesting was the parallel between repeated application of patches to an empty tree and

    • the repeated application of patterns to a design, leading to piecemeal growth of a system, and
    • the agile methods' cyclic process of extension and refactoring.

    This led me to think about how an IDE such as Eclipse might have version control build right into it. Each time the programmer adds new behavior or applies a refactoring, the change can be recorded as a patch, a diff to the previous system. The theory of patches needed for a version control system like Darcs would be directly useful in implementing such a system.

    I used to program a lot in Smalltalk, and Smalltalk's .changes file served as a lightweight, if incomplete, version control system. I suppose that a Smalltalker could implement something more complete rather easily. Someone probably already has!

    Thanks to Chad Fowler's bookmarks for the link.


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

    November 30, 2004 5:48 PM

    Milestones and Nostalgia

    November 2004 will enter the books as my least-blogged month since starting Knowing and Doing back in July. I'm not all that surprised, given that:

    • it is the last full month of my semester,
    • it follows a month in which I was on the road every weekend and for a full week at OOPSLA, and
    • it contains a 5-day week for Thanksgiving.
    Each of these would cut into my time for blogging on its own, and together they are a death knell to any free moments.

    When I started Knowing and Doing, I knew that regular blogging would require strict discipline and a little luck. Nothing much has changed since then. I still find the act of writing these articles of great value to me personally, whether anyone reads them or not. That some folks do find them useful has been both gratifying and educational for me. I learn a lot from the e-mails I receive from Faithful Readers.

    I reached the 100-post plateau ten days ago with this puff piece. I hope that most of my posts are of more valuable than that! In any case, reaching 1000 entries will be a real accomplishment. At my current pace, that will take me three more years...

    While on this nostalgic kick, I offer these links as some obligatory content for you. Both harken back to yesteryear:

    • Brian Foote waxes poetic in his inimitable way about watching undergrads partake in the rite of initiation that is a major operating systems project. He points out that one thing has changed this experience significantly since he and I went through it thirty and (can it be?) twenty years ago, respectively: unit tests.

    • John O'Conner has a nice little piece on generalizing the lesson we all learned -- some of us long ago, it seems -- about magic numbers in our code. Now if only we turned all those constants into methods a lá the Default Value Method pattern...


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

    November 29, 2004 4:46 PM

    Accepting the Blame

    On Saturday, Jason Yip started a conversation about the danger of accepting blame reflexively. He fears that accepting the blame preemptively "reinforc[es] the mistaken belief that having someone take blame is somehow important." Fixing the problem is what matters.

    This is, of course, true. As Jerry Weinberg says in The Secrets of Consulting:

    The chances of solving a problem decline the closer you get to finding out who was the cause of the problem.

    (You may recall that some of my earliest blog entries here and here referred to this gem of a book.)

    When people focus on whose fault it is, they tend to become defensive, to guard their egos, even at the expense of fixing the problem. This is a very human response, and one that is hard to control intellectually. The result is both that the problem remains and its systematic cause remains, pretty much guaranteeing more problems in the future. If we can depersonalize the problem, focusing on what is wrong and how we can fix it, then there is hope of both solving the problem and learning how not to cause similar problems in the future.

    I think Jason is right on that people can use "It's my fault" as a way to avoid discussion and thus be as much of an obstacle to growth and improvement as focusing on placing blame. And someone who *always* says this is either trying to avoid confrontation or making way too many mistakes. :-)

    But as one commenter posted on his site, saying "I made a mistake. Let's fix it, and let's find a way to avoid such problems in the future" is a welcome behavour, one that can help individuals and teams grow. The real problem is saying "I made a mistake." when you didn't make a mistake or don't want to discuss what you did.

    I have been fortunate never to have worked at a place where people played The Blame Game, at least not too destructively. Walking on eggshells all day is no way to live one's life, and not the sort of environment in which a person can learn.

    These days, I don't have much trouble in professional settings acknowledging my mistakes, though I probably wasn't always as easy-going. I give a lot of credit for my growth in this regard to having papers I've written workshopped at PLoP conferences. At PLoP, I learned how better to separate my self from my product. The practices of writers workshops aim to create a safe environment, where authors can learn about how well their papers work. As much as the practices of the patterns community help, it probably takes going through the workshop process a few times to wear away the protective shell that most of use use to protect ourselves from criticism. Being with the right sort of people helps.

    All that said, I had to chuckle at It's Chet's Fault, a fun little community practice of the famed C3 project that gave rise to XP as a phenomenon. On a team of folks working together to get better, I think that this sort of levity can help people remember to keep their eyes on what really matters. On the other hand, lots of things can work with a team of folks striving to get better. Being with the right sort of people helps.


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

    November 22, 2004 9:45 AM

    What Does the iPod have in Common with Prego Spaghetti Sauce?

    While waiting for the UNI's first men's basketball game of the year to begin yesterday, I read a couple of articles I'd found while surfing the blogosphere. I was surprised to run across the same Big Idea in both papers, albeit it in different forms:

    Design, well done, satisfies needs users didn't know they had.

    I found it first in Paul Graham's new essay, Made in USA. Graham relates how he felt after buying an iPod:

    I just got an iPod, and it's not just nice. It's surprisingly nice. For it to surprise me, it must be satisfying expectations I didn't know I had. No focus group is going to discover those. Only a great designer can.

    The essay itself is about why the US is good at designing some things, like software, and bad at others, like cars. Graham's diagnosis: Americans don't care much for taste or quality. Instead of relying on a sense of good design, American auto manufacturers rely on focus groups to tell them "what people want".

    So why is the US good at designing other products, such as software? Americans are driven by speed, and some products are done better when done quickly without undue emphasis on getting it "right". Indeed, when I read the essay, the quote that most struck me wasn't the one about the iPod, but this one:

    In software, paradoxical as it sounds, good craftsmanship means working fast. If you work slowly and meticulously, you merely end up with a very fine implementation of your initial, mistaken idea. Working slowly and meticulously is premature optimization. Better to get a prototype done fast, and see what new ideas it gives you.

    What a nice crystallization of the spirit of agile development: If you work slowly and meticulously, you merely end up with a very fine implementation of your initial, mistaken idea. Working slowly and meticulously is premature optimization.

    Graham points to Steve Jobs as an exception to this general rule about technological fields and offers hope that American designers who care about quality and craftsmanship can succeed. Of course, Apple, has never been more than a niche player in the market for computer software and hardware (a niche in which I proudly reside).

    Next, I found myself reading Malcolm Gladwell's recent The Ketchup Conundrum. Yes, an article about ketchup. Actually, it's about mustard, too, and Prego spaghetti sauce. When Campbell's Soup was trying to reinvigorate its Prego-brand sauce in the late 1980s, they brought in an unconventional market researcher named Howard Moskowitz to inject some new ideas in their approach. This quote caught my eye (emphasis added):

    Standard practice in the food industry would have been to convene a focus group and ask spaghetti eaters what they wanted. But Moskowitz does not believe that consumers -- even spaghetti lovers -- know what they desire if what they desire does not yet exist. "The mind," as Moskowitz is fond of saying, "knows not what the tongue wants."

    Moskowitz uses focus groups -- Graham's bane -- but with a twist. Rather than have the Prego folks create what they think people want and then taste-test it against standard sauces, Moskowitz had the Prego folks create forty-five varieties of Prego, in all the different combinations they could think of. Then ran these varieties against a panel of trained food tasters before taking the options to the people.

    In many ways, this is exactly the opposite of the Jobs approach, which relies on a genius designer to assess the state of the world and create a product that scratches an itch no one quite knew they had. The Moskowitz approach is more in the Art and Fear philosophy, to produce a lot of artifacts. Many will have no shelf life, but in the volume you are more likely to create something of value. Not stated in the Gladwell article is another potential benefit of Moskowitz's approach: in producing lots of stuff, designers overcome the fear of creating, especially things that are different from what already exists. Even better, such designers can begin to develop a sense of what works and what doesn't through voluminous experience.

    Design, well done, satisfies needs users didn't know they had. And you can do it well in different ways.


    Posted by Eugene Wallingford | Permalink | Categories: Software Development

    November 21, 2004 11:23 AM

    The Psychology of Long Runs and Long Iterations

    This morning I went out for a 12-mile run. That's my usual Sunday morning run when I'm not training for a marathon, part of my "maintenance mileage" year 'round. But before today I had run this far only once since running the Des Moines Marathon, plus I've been dragging a bit from running faster the last couple of weeks. So this morning I planned for a little LSD. That's long slow distance, not the psychotropic drug, though both can lead to out-of-body experiences.

    Forty-eight minutes into the run, I felt a little discouraged. I still had a little over an hour to go! But then I thought, you run almost 48 minutes even on your shortest days; what's the big deal? The big deal was that that second thing: I still had a little over an hour to go. The psychology of a long run is much different than the psychology of a short run. That's what makes marathons so challenging.

    Then I got to thinking about the psychology of long and short runs in software development. I wonder if the short iterations encouraged by agile methodologies help to buttress the morale of developers on those days and projects that leave them feeling down? I've certainly worked on traditional software projects where the thought of another six months before a release seemed quite daunting. Working from a state of relative uncertainty is no fun. On agile projects, we at least get to issue releases more frequently and incorporate feedback from the customer into the next iterations.

    Sometimes, running requires endurance. If you want to run a marathon, then you had better get ready to run for 3, 4, or 5 hours. I suppose that big software projects require stamina, too. A year-long project will take a year whether done in many short releases or in one big one. But the closer horizon of short iterations can be comforting, even without considering the value of continuous feedback.

    With my mind occupied thinking about software and psychology, pretty soon my run was over. I was tired, as expected, and a little stiff. But I felt good for having done 12. My next 45-minute iteration happens on Tuesday.


    Posted by Eugene Wallingford | Permalink | Categories: Running, Software Development

    November 19, 2004 10:10 AM

    Of Roosters and Running

    From Art and Fear:

    In talking about how hard artists work, I am reminded of the story about the man who asked a Chinese artist to draw a rooster for him and was told to come back in a month. When he returned, the artist drew a fabulous rooster in a few minutes. The man objected to paying a large sum of money for something that took so little time, whereupon the artist opened the door to the next room in which there were hundreds of drawings of roosters.

    Sometimes folks, non-runners and runners alike, comment on how they can't run as far or as fast (hah!) as I do. There are days when I wish that I could open a door to let the person see a room full of runs like the one I had this morning: hard work, pushing at my limits, finishing with nothing left, but still short of the goal I've been working toward.

    Folks who make this sort of comment almost always mean well, intending a compliment. Often, though, I think that the unstated implication is that they couldn't do what I do even if they tried, that runners have some innate ability that sets them apart from everyone else. Now, I don't doubt at all that some people have innate physical abilities that give them some advantage at running. The very best -- the guys who run 9.9s in the 100m, or 2:10 marathons -- almost certainly have gifts. But I am not a gifted runner, other than having the good fortune to not injure easily or get sick very often.

    And let's not forget how hard those 9.9s sprinters and 2:10 marathoners have to work in order to reach and maintain their level of excellence.

    Richard Gabriel often says that "talent determines only how fast you get good, not how good you get". Good poems, good art, and good runs are made by ordinary people. Art and Fear says this: "Even talent is rarely distinguishable, over the long run, from perseverance and lots of hard work."

    That is good news for runners like me. Maybe, if I keep working, I'll reach my speed goal next week, or the week after that.

    It's also good news for programmers like me.

    Computer science students should take this idea to heart, especially when they are struggling. Just keep working at it. Write programs every day. Learn a new something every day. You'll get there.


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

    November 12, 2004 10:26 AM

    Fixin' What's Broke

    On Wednesday I blogged about helping students succeed more by cutting their projects in half. I haven't tried that yet, but I did take a small step in that spirit, toward helping students learn in a different way than usual.

    In my agile development course, we've been reading The Pragmatic Programmer, and recently discussed the idea that professionals are masters of their tools. I've been encouraging students in the course to broaden their skill sets, including both tools specific to the agile arena, such as JUnit, and tools more general to their professional needs, such as a command shell, an editor, and a couple of programming languages. But I find that most students (have to) focus so much on the content of their programming assignments that they don't attend much to their practices.

    So, I made their latest assignment be specifically to focus on skills. They will use a new tool (a testing framework other than JUnit) to work with a program they've already written and to write a very simple program. At the same time, they are to choose a particular skill they want to develop -- say, to learn emacs or to finally learn how to use a Linux command line -- and do it. With almost no content to the assignment, at least not new content, I hope that students will feel they have the time and permission to focus on developing their skills.

    I am reminded of one of my favorite piano books, Playing the Piano for Pleasure, by Charles Cooke (Simon and Schuster, 1941). Cooke was a writer by trade but an ardent amateur pianist, and he used his writing skills to share some of his secrets for studying and practicing piano. Among other things, Cooke suggested a technique in which he would choose his weakest part of a piece, what he calls a 'fracture', and then practice it with such intensity and repetition that it becomes one of his strongest. He likened this to a bone healing after a fracture, when the newly knitted bone exceeds the strength of the bone around it.

    I try to have this mindset when working on my professional skill set. And I'd certainly like my students to grow toward such a mentality as they develop into software professionals and happy adults.

    I hope that some of the students working on my new assignment will attack their own weakest areas and turn them into strengths or, at the least, grow to the point that they no longer have to fear the weakness. Overcoming even a little fear can help a student move a long way toward being a confident and successful programmer.


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

    November 10, 2004 10:46 AM

    An Instant Recipe for Success -- for Students and Professors?

    I liked Incipient Thought's recipe for project success yesterday.

    It starts with T. J. Watson's well-known:

    If you want to increase your success rate, double your failure rate.

    ... to which he adds a second part:

    If you want to double your failure rate, all you have to do is halve your project length.

    Then, winking, he points out that the second step may fail, because shorter projects may actually succeed more often!

    I think this is wonderful software development advice.

    As a teacher, I have been thinking about how to bring this idea to my courses and to my students.

    I always encourage my students to approach their course projects in this way: take lots of small steps doing the simplest thing possible, writing test code to verify success at each step, and refactoring frequently to improve their design. By taking small steps, they should feel confident that whatever they've done so far actually works. And, when it doesn't, they haven't gone too far astray, because they only worked on a little bit of specification. Debugging can often be localized to the most recently added code.

    Breaking a complex but unitary spec ("implement a program to play MasterMind") down into smaller stories is hard, especially for freshmen and sophomores. Even my upper division students sometimes have difficulty breaking requirements that are smaller but still too big into even smaller steps.

    In recent semesters, I've tried to help by writing my assignments as a list of small requirements or user stories. My second-semester students are currently implementing a simple text-based voice mail system, which I specified as a sequence of individual requirements. Sometimes, I even specify that we will grade assignments story-by-story and stop as soon as the program "fails" a story.

    This approach sounds great, but it is out of step with the student culture these days. Taking small steps, and especially refactoring, requires having a certain amount of time to go through the process, with some reflection at each step. Most students are inclined to start every project a few days or less before it's due, at which point they feel a need to "just do it". I've tried to encourage them not to postpone starting -- don't all professors face this problem? -- mostly to no avail.

    In my Agile Software Development course, we've been doing 2- and 3-week releases, and I think we've had some success with doing 3 week-long iterations, with full submission of the project, within each release. Even still, word in the class is that many folks start each iteration on a day or two or three before it's due.

    Maybe I should take the "recipe for project success" advice for them... I could assign two half-week assignments instead of a one-week assignment! Students would have twice as many opportunities to succeed, or to fail and learn.

    One of the downsides of this idea for me is grading. I don't like to grade and, while am usually (but not always!) timely in getting assignments back to students, I use enough mental energy grading for three courses as it is. I could automate more of the grading, using JUnit, say, to run tests against the code. But to the extent that I need to look at their code, this approach requires some new thinking about grading.

    One of the downsides of this idea for my students is the old time issue. With 15 hours of class and 30 hours at work and whatever time they spend in the rest of their lives, students have a tough time working steadily on each course throughout each week. Throw in exams and projects and presentations during special times in the semester, and the problem gets worse.

    But I can't shake the feeling that there is something deeply right about halving the size of every project. I may have to "just do it" myself and face whatever difficulties arise as they do.


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

    November 06, 2004 9:03 PM

    Alan Kay's Talks at OOPSLA

    Alan Kay gave two talks at OOPSLA last week, the keynote address at the Educators Symposium and, of course, his Turing Award lecture. The former was longer and included most of the material from the Turing lecture, especially when you consider his generous question-and-answer session afterwards, so I'll just comment on the talks as a single presentation. That works because they argued for a common thesis: introductions to computing should use simple yet powerful computational ideas that empower the learner explore the larger world of ideas.

    Kay opened by decrying the premature academization of computing. He pointed out that Alan Perlis coined the term "computer science" as a goal to pursue, not as a label for existing practice, and that the term "software engineering" came with a similar motivation. But CS quickly ossified into a discipline with practices and standards that limit intellectual and technical discovery.

    Computing as science is still an infant. Mathematicians work in a well-defined space, creating small proofs about infinite things. Computing doesn't work that way: our proofs are programs, and they are large, sometimes exceedingly so. Kay gave a delightful quote from Donald Knuth, circa 1977:

    Beware of bugs in the above code; I have only proved it correct, not tried it.

    The proof of our programs lies in what they do.

    As engineering, computing is similarly young. Kay contrasted the construction of the Great Pyramid by 200,000 workers over 20 years with the construction of the Empire State Building by fewer than 3,000 people in less than 11 months. He asserts that we are somewhere in the early Middle Ages on that metaphorical timeline. What should we be doing to advance? Well, consider that the builders of the Pyramid used hand tools and relatively weak ideas about building, whereas the engineers who made the Empire State Building used power tools and even more powerful ideas. So we should be creating better tools and ideas. (He then made a thinly veiled reference to VisualStudio.NET 2005, announced at OOPSLA, as just another set of hand tools.)

    So, as a science and professional discipline in its youth, what should computing be to people who learn it? The worst thing we can do is to teach computer science as if it already exists. We can afford to be humble. Teach students that much remains to be done, that they have to help us invent CS, that we expect them to do it!

    Kay reminded us that what students learn first will have a huge effect on what they think, on how they think about computing. He likened the effect to that of duck imprinting, the process in which ducklings latch onto whatever object interacts with them in the first two days of their lives -- even if the object is a human. Teaching university students as we do today, we imprint in them that computing is about arcane syntax, data types, tricky little algorithms, and endless hours spent in front of a text editor and compiler. It's a wonder that anyone wants to learn computing.

    So what can we do instead? I ran into some interesting ideas on this topic at OOPSLA even before the Educators' Symposium and had a few of my own during the week. I'll be blogging on this soon.

    Alan has an idea of the general direction in which we should aim, too. This direction requires new tools and curricula designed specifically to introduce novices to the beauty of computing.

    He held up as a model for us Frank Oppenheimer's Exploratorium, "a collage of over 650 science, art, and human perception exhibits." These "exhibits" aren't the dead sort we find in most museums, where passive patrons merely view an artifact, though. They are stations with projects and activities where children can come face to face with the first simple idea of science: The world is not always as it seems. Why are there so many different exhibits? Kay quoted Oppenheimer to the effect that, if only we can bring each student into contact with that one project or idea that speaks directly to her heart, then we will have succeeded.

    Notice that, with that many projects available, a teacher does not have to "assign" particular projects to students at a particular point in time. Students can choose to do something that motivates them. Kay likened this to reading the classics. He acknowledged that he has read most of the classics now, but he didn't read them in school when they were assigned to him. Then he read other stuff, if only because the he had chosen for himself. One advantage of students reading what they want is that a classroom will be filled with people who have read different things, which allows you to have an interesting conversation about ideas, rather than about "the book".

    What are the 650 examples or projects that we need to light a fire in every college student's heart? Every high schooler? Every elementary school child?

    Kay went on to say that we should not teach dumbed-down versions of what experts know. That material is unnecessarily abstract, refined, and distant from human experience. Our goal shouldn't be to train a future professional computer scientist (whatever that is!) anyway. Those folks will follow naturally from a population that has a deep literacy in the ideas of science and math, computing and communication.

    Here, he pointed to the typical first course in the English department at most universities. They do not set out to create professional writers or even professional readers. Instead, they focus on "big ideas" and how we can represent and think about them using language. Alan thinks introductory computer science should be like this, too, about big ideas and how to represent and think about them in language. Instead, our courses are "driver's ed", with no big ideas and no excitement. They are simply a bastardization of academic computer science.

    What are the big ideas we should introduce to students? What should we teach them about language in order that they might represent ideas, think about them, and even have ideas of their own?

    Alan spent quite a few minutes talking about his first big inspiration in the world of computing. Ivan Sutherland's Sketchpad. It was in Sketchpad that Kay first realized that computing was fundamentally a dynamic medium for expressing new ideas. He hailed Sutherland's work "the greatest Ph.D. dissertation in computer science of all time", and delighted in pointing out Sketchpad's two-handed user interface ("the way all UIs should be"). In an oft-told but deservedly repeated anecdote, Kay related how he once asked Sutherland how he could have created so many new things -- the first raster graphics system, the first object-oriented system, the first drawing program, and more -- in a single year, working alone, in machine language. Sutherland replied, "... because I didn't know it was hard".

    One lesson I take from this example is that we should take care in what we show students while they are learning. If the see examples that are so complex that they can't conceive of building them, then they lose interest -- and we lose a powerful motivator.

    Sutherland's dissertation includes the line, "It is to be hoped that future work will far surpass this effort". Alan says we haven't.

    Eventually, Kay's talk got around to showing off some of the work he and his crew have been doing at Squeakland, a science, math, and computing curriculum project built on top of the modern, open source version of Smalltalk, Squeak. One of the key messages running through all of this work can be found in a story he told about how, in his youth, he used to take apart an old Model T Ford on the weekend so that he could figure out how it worked. By the end of the weekend, he could put it back together in running condition. We should strive to give our students the same experience in the computing environments they use: Even if there's a Ferrari down there, the first thing you see when you open the hood is the Model T version -- first-order theories that, even if they throw some advanced ideas away, expose the central ideas that students need to know.

    Alan demoed a sequence of increasingly sophisticated examples implemented and extended by the 5th- and 6th-grade students in B.J. Conn's charter school classes. The demos in the Educators' Symposium keynote were incredible in their depth. I can't do them justice here. The best you can do is to check out the film Squeakers, and even that has only a small subset of what we saw in Vancouver. We were truly blessed that day!

    The theme running through the demos was how students can explore the world in their own experience, and learn powerful ideas at the "hot spot" where math and science intersect. Students can get the idea behind tensor calculus long before they can appreciate the abstractions we usually think of as tensor calculus. In the course of writing increasingly complex scripts to drive simulations of things they see in the world, students come to understand the ideas of the variable, feedback, choice, repetition, .... They do so by exposing them in action, not in the abstract.

    The key is that students learn because they are having fun exploring questions that matter to them. Sometime along in here, Kay uttered what was for me the Quote of the Day, no, the Quote of OOPSLA 2004:

    If you don't read for for fun, you won't be fluent enough to read for purpose.

    I experience this every day when interacting with university students. Substitute 'compute' or 'program' for 'read', and you will have stated a central truth of undergraduate CS education.

    As noted above, Kay has a strong preference for simple, powerful ideas over complex ideas. He devoted a part of his talk to the Hubris of Complexity, which he believes long ago seduced most folks in computing. Software people tend to favor the joy of complexity, yet we should strive for the joy of simplicity.

    Kay gave several examples of small "kernels" that have changed the world, which all people should know and appreciate. Maxwell's equations were one. Perhaps in honor of the upcoming U.S. elections, he spent some time talking about the U.S. Constitution as one such kernel. You can hold it in the palm of your hand, yet it thrives still after 225 years. It is an example of great system design -- it's not law-based or case-based, but principle-based. The Founding Fathers created a kernel of ideas that remains not only relevant but also effective.

    I learned a lot hearing Alan tell some of the history of objects and OOP. In the 1960s, an "object" was simply a data structure, especially one containing pointers. This usage predates object-oriented programming. Alan said that his key insight was that an object could act as a miniature software computer -- not just a data structure, not just a procedure -- and that software scales to any level of expression.

    He also reminded us of something he has said repeatedly in recent years: Object-oriented programming is about messages, not the objects. We worry about the objects, but it's the messages that matter.

    How do we make messages the centerpiece of our introductory courses in computing?

    Periodically throughout the talk, Alan dropped in small hints about programming languages and features. He said that programming language design has a large UI component that we technical folks sometimes forget. A particular example he mentioned was inheritance. While inheritance is an essential part of most OOP, Alan said that students should not encounter it very soon in their education, because it "doesn't pay for the complexity it creates".

    As we design languages and environments for beginners, we can apply lessons from Mihaly Csikszentmihalyi's idea of "flow". Our goal should be to widen the path of flow for learners. One way to do that is to add safety to the language so that learners do not become anxious. Another is to create attention centers to push away potential boredom.

    Kay's talks were full of little nuggets that I jotted down and wanted to share:

    • He thanked many people for participating in the creation of his body of work, sharing with them his honors. Most notably, he thanked Dan Ingalls "for creating Smalltalk; I only did the math". I have often heard Alan single out Ingalls for his seminal contributions. That makes a powerful statement about the power of teams.

    • Throughout the talk, Alan acknowledged many books and ideas that affected him. I couldn't get down all of the recommended reading, but I did record a few:
      • Bruce Alberts, "Molecular Biology of the Cell"
      • Lewis Carroll Epstein, "Relativity Visualized"
      • James D. Watson, "Molecular Biology of the Gene"

    • Clifford Shaw's JOSS was the most beautiful programming language ever created. I've heard of JOSS but now have to go learn more.

    • Whatever you do, ask yourself, "What's the science of it?" You can replace 'science' with many other words to create other important questions: art, math, computing, civilization.

    • "In every class of thirty 11-year-olds, there's usually one Galileo kid." What can we do to give him or her the tools needed to redefine the world?

    Alan closed both talks on an inspirational note, to wrap up the inspiration of what he had already said and shown us. He told us that Xerox PARC was so successful not because the people were smart, but because they had big ideas and had the inclination to pursue them. They pursued their ideas simple-mindedly. Each time they built something new, they asked themselves, "What does the complexity in our system buy us?" If it didn't buy enough, they strove to make the thing simpler.

    People love to quote Alan's most famous line, "The best way to predict the future is to invent it." I leave you today with the lines that follow this adage in Alan's paper "Inventing the Future" (which appears in The AI Business: The Commercial Uses of Artificial Intelligence, edited by Patrick Henry Winston and Karen Prendergast). They tell us what Alan wants us all to remember: that the future is in our hands.

    The future is not laid out on a track. It is something that we can decide, and to the extent that we do not violate any known laws of the universe, we can probably make it work the way that we want to.

    -- Alan Kay, 1984

    Guys like Alan set a high bar for us. But as I noted last time, we have something of a responsibility to set high goals when it comes to computing. We are creating the medium that people of the future -- and today? -- will use to create the next Renaissance.


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

    November 03, 2004 3:47 PM

    Other Folks Comment on OOPSLA

    Some other folks have blogged on their experiences at OOPSLA last week. These two caught my attention, for different reasons.

    The trade-off between power and complexity in language

    Nat Pryce writes about stopping on the SeaSide BoF. SeaSide is a web app framework written in Smalltalk. Nat marvels at its elegance and points out:

    SeaSide is able to present such a simple API because it takes advantage of "esoteric" features of its implementation language/platform, Smalltalk, such as continuations and closures. Java, in comparison to Smalltalk, is designed on the assumption that programmers using the Java language are not skilled enough use such language features without making a mess of things, and so the language should only contain simple features to avoid confusing our poor little heads. Paradoxically, the result is that Java APIs are overly complex, and our poor little heads get confused anyway. SeaSide is a good demonstration that powerful, if complex, language features make the job of everyday programming easier, not harder, by letting API designers create elegant abstractions that hide the complexity of the problem domain and technical solution.

    There is indeed great irony in how choosing the wrong kind of simplicity in a language leads to unnecessary complexity in the APIs and systems written in the language. I don't have an opportunity to teach students Smalltalk much these days, but I always hope that they will experience a similar epiphany when programming in Scheme.

    Not surprisingly, Alan Kay has a lot to say on this topic of simplicity, complexity, and thinking computationally, too. I hope to post my take on Alan's two OOPSLA talks later this week.

    Making Software in a Joyous World

    You gotta love a blog posting subtitled with a line from a John Mellencamp song.

    Brian Marick writes about three talks that he heard on the first day at OOPSLA. He concludes wistfully:

    I wish the genial humanists like Ward [Cunningham] and the obsessive visionaries like Alan Kay had more influence [in the computing world]. I worry that the adolescence of computers is almost over, and that we're settling into that stagnant adulthood where you just plod on in the world as others made it, occasionally wistfully remembering the time when you thought endless possibility was all around you.

    In the world where Ward and Alan live, people use computing to make lives better. People don't just consume ideas; they also produce them. Ward's talk described how programmers can change their world and the world of their colleagues by looking for opportunities to learn from experience and creating tools that empower programmers and users. Alan's talk urged us to take that vision out into the everyone's world, where computers can serve as a new kind of medium for expressing new kinds of ideas -- for everyone, not just software folks.

    This are high goals to which we can aspire. And if we don't then who else will be able to?


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

    October 31, 2004 4:15 PM

    Software Development Fantasies

    Don't worry. This entry is rated G, for general audiences.

    The last session of the Onward! track at OOPSLA was a panel-turned-open-mike called Breakthrough Ideas. The idea was simple: Anyone could take the mike for four minutes or less and propose something that would, if true or made so by future development, fundamentally alter the way we use computers, program them, or view computation. The four-minute limit was strictly enforced in order to cycle through as many ideas as possible in the ninety minute session, and to prevent the inevitable rambling that ensues when some of us start talking about some idea yet ill-formed in our minds. The format can't eliminate rambling, only cut it off.

    A few of the proposed ideas made me smile and want to think about them further:

    • programmed program death: build into each piece of code an expiration date or a dying process so that, at the appointed time, the code goes away. (So much for the Y2K problem!)

    • a Pulitzer Prize for wonderful code, code that is elegant, understated, understandable, beautiful. The genre categories might be application areas or, more likely, languages. In order to appreciate the beauty of most code, you have to speak the language.

    • program our computer tools to ask us questions, rather than waiting for us to fill in every details and, in the process, make mistakes.

    • programming on the model of a research professor: when you need a program, you delegate to a graduate student. What would that be like between me and my computer?

    • an oldie but a goodie: the whiteboard compiler.

      But maybe we are getting closer on this one... A poster on the Squeak list recently said that he now uses Squeak for much of his creative work. He can't throw his pencils and paper out quite yet, but he feels like he's getting closer. Alan Kay's talks certainly encouraged us to think about how we can make progress toward this goal.

    Some other ideas immediately became questions in my mind, either because I didn't understand the proposal or because the proposal really was a question.

    What would it be like to write software on the model of living organisms? Software these days has hard edges -- rigid interfaces -- that delineate the boundaries of each functional component, which does its job and nothing else. But biological systems have soft edges and seem to operate on the premise that components fail all the time. (See Brian Marick's body-as-kludge article.) Their components also differ from software in that, say, a liver consists of oodles of liver cells, none of which are a liver but which in concert act as a liver -- with primary and secondary and tertiary functions intermingled.

    Finally, what would you do if you knew that one billion people would use your software? For starters, you would probably have to make the program multilingual down to its foundations... Or would you?

    I think it's neat that some people think thoughts like these, and that at least a few of them are even actively pursuing answers...


    Posted by Eugene Wallingford | Permalink | Categories: Software Development

    October 30, 2004 11:26 AM

    Knowing and Seeing

    Brian Marick's talk on methodology work as ontology work sounds more forbidding than it is. His central point is this: whenever adopt a particular software development approach, or create a new one (that's the methodology part), we implicitly take on, or promote, a particular way of seeing the world (that's the ontology part). One implication of this is that communication between folks in different methodology camps -- say, XPers and more traditional software engineers -- is often difficult precisely because these folks see the world differently. They can look at the same project or team or testing scenario and see different things. To help such folks communicate better, you must often help them to build a common vocabulary, or at least recognize the names collisions in their individual vocabularies.

    Coming to know is to change how we perceive the world.

    Those of us in AI community came to learn this up close and personal through the 1970s, '80s, and early '90s. While many of us built useful and usable knowledge-based systems using techniques that codify knowledge in the form of rules or other explicit structures, we soon learned the limits of these approaches. Experts don't have rules for doing their job; they just do it. The same is true for everyday knowledge. You don't have an algorithm for determining whether you are tired. You merely know it.

    Merely. In learning, you lose the rules and learn to see something new.

    Another implication of this view is that we can often use perception to drive behavior better than rule-based prescriptions. Brian gave two examples:

    • Big Visible Charts are a better way for a team to know the bugs that need to be fixed than annotations in code like "TODO" comments.
    • JUnit's red bar/green bar metaphor is better than just a numeric output on a list.

    As always, I liked Brian's talk for his broad scholarship and skills making connections. For example, I learned that scientists like research programs:

    • that have a "hard core", a small, tightly connected set of assumptions. This point echoed Alan Kay's love of "kernels" such as Maxwell's equations.
    • that work out consequences of their theories and 'ignore' counterexamples as potential refutation. That sounds counter to what we often learn about the falsifiability of scientific theories, but it is really a sign of a deep commitment to the simple idea that underlies a theory.
    • that make novel or surprising predictions which are subsequently confirmed. One such confirmation can often trump dozens of little counterexamples based on the details of a theory's explication.

    We have a lot to learn from the philosophy of science.


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

    October 28, 2004 12:39 PM

    The Experience of Programming

    [ I wrote this last night but wasn't able to post it then. Why? Stay tuned. ]

    After the Steve McConnell talk this morning, I went to three technical events:

    • an Onward! session on changing the experience of programming.

      Jonathan Edwards talked about example-centric programming, and in particular two tools he has built: EG, an Eclipse plug-in for integrating examples directly into code and the IDE, and subtext, a language for programming in an example-centric way. The neat idea here is one I've seen elsewhere, that text strings are not the right way to represent programs. A structured format offers some interesting possibilities for writing code.

      David Hovemeyer spoke about FindBugs, a static analyzer of Java programs that finds common bugs based on common bug patterns the authors have identified.

    • an Onward! panel on transforming the software lifecycle. It was entertaining in a way, but I have nothing to say about it.
    • a panel on whether software development is (math and science) or (arts and crafts). Engineering wasn't in the title, which upset a few folks. The panel was high-powered -- Robert Biddle, Martin Fowler, Dick Gabriel, Ralph Johnson, and Steve McConnell -- and there was some interesting stuff said, especially by Biddle on English literature -- but mostly it didn't give insights that haven't been given before at many events of this sort. The key lesson is something I blogged a couple of weeks ago: Metaphors can both help and limit us in our discovery. Use with care.

    The evening has been BoFs. The first was for the Domain Driven Design community. Eric Evans published the marvelous book of this title last year (read it!), and he has cultivated an on-line community around the idea. I have volunteered to help out by serving as an editor and light writer for the FAQ on the web site's wiki. I have so much free time... but this is an idea and a community I want to support.

    The second -- going now -- is for planning the OOPSLA 2005 conference. I agreed to chair the Educators Symposium again. Giddy-up!

    Up next is a fun event at the Vancouver Aquarium, of which I've heard many good things. I'm ready for a break.


    Posted by Eugene Wallingford | Permalink | Categories: Software Development

    October 27, 2004 1:11 PM

    Steve McConnell on the Realities of Software Construction

    Let's try this blogging thing in real time. Steve McConnell, author of the recent bestseller Code Complete 2, is giving the opening talk for Day 2 of OOPSLA. The first edition of Code Complete is a classic in the field, still cited by software engineers and practitioners.

    McConnell opened with some humor on the hazards of renaming a book called 'complete'. The best ones played off cultural icons: Davinci Code Complete and Code Complete: This Time It's Personal.

    The first part of the talk gave several lists summarizing the software world since Code Complete, the prequel, came out. A lot of the humor and insight in these lists lay in how some items showed up multiple times, or in how opposites showed up.

    The worst construction ideas of the 1990s

    • code and fix
    • Big Design Up Front (Back then, it was *all* design up front.)
    • designing programs based on speculative requirements
    • the belief that components will solve all our problems (Just as Biddle and Noble's postmodernism theme tells us, there is no one story that can account for all we can or should do.)
    • automatic programming
    • calling everything "object-oriented"

    The worst construction ideas of the 2000s, so far

    • code and fix
    • no design up front
    • planning to refactor, usually meant as fixing code
    • the belief that offshore outsourcing will solve all of our problems
    • automatic programming
    • uninformed use of extreme programming (An informed use of the waterfall approach is likely better uninformed use of extreme programming.)
    • calling everything "agile"

    But not everything in the software world is bad...

    A decade of advances in software development

    • With the theatrical release of The Lord of the Rings, all companies now have servers named 'gandalf' and 'frodo'.

    • We now do design at a higher level. Indeed, this may be the ultimate legacy of OO: we design our systems in terms of larger aggregations or abstractions.

    • The daily build and smoke test minimizes integration problems and institutionalizes incremental development.

    • There is now accepted, widespread use of standard libraries.

    • The creation of VisualBasic has brought several advances to common use in the public: visual programming, widespread use of COTS components, and improved control constructs that learned from Ada language design principles.

    • open source software

    • the web as a research tool

    • the widespread use of incremental development

    • Test-first design shortens time to defect detection and increases personal discipline.

    • Refactoring as a discipline, not as a cop-out, improves the design of software.

    • Faster computers have radically changed how we have to think about software development. Computers are so much faster than they used to be (McConnell spoke of having to perform test code 5 million times just to get measurable results!) that we should no longer think about optimization at the code level. It is almost never worth the effort. We can now pay attention to optimization primarily at the design level. Machine speed also means that we can use languages that we like, that make us more productive, without having to worry about the speed of interpreters, compilers, and compiled code.

    I'm not going to report all of McConnell's ten realities of modern software construction, but I will summarize some of the points that struck me:

    • Construction is a legitimate topic of discussion as an activity, a set of practices, separate from the other parts of software development.

    • Personal discipline matters -- in the form of making realistic predictions, refactoring code, and creating simple designs. McConnell didn't mention writing tests, but I think it belongs here, too. He did point out that, while many folks think of Ward Humphrey and Kent Beck as representing very different sorts of software methodology, perhaps at opposite ends of a continuum, the discipline of Humphrey's PSP and the courage of Kent's XP are in much the same spirit. I think that this is a great insight. XP is not high ceremony, but it is high discipline. I once asked Kent what one new practice I should introduce into my first-year courses, and he said, "Have your students keep a project notebook", so that students could record their behaviors and be able to examine and improve them. Not so much different than PSP.

    • The fundamental tension in software is between simplicity and complexity. In the trade-off between write-time convenience and read-time convenience, the former is worth essentially nothing, given how much more code is read than written.

    • The toolbox metaphor gives us great power. We should keep that in mind when thinking about our development methodologies.

    Talk Complete. (That was McConnell's joke, not mine. :-)


    Posted by Eugene Wallingford | Permalink | Categories: Software Development

    October 15, 2004 2:57 PM

    What Is It Like to Make Software?

    Earlier this week, my students and I discussed a chapter from The Pragmatic Programmer. A few students wrinkled their noses at Dave and Andy's use of gardening as a metaphor for software development. I know lots of folks who don't like this and other "soft" metaphors for making software. For most folks, engineering and architecture still make the most sense.

    At one level, of course, software development is like engineering. Software developers design and build artifacts in response to human needs. They base their designs on a scientific and mathematical understanding of the world. They strive for processes that are verifiable and repeatable, so that they can reliably build artifacts that meet their specifications.

    But, as I admitted to my students almost in a whisper, I like the gardening metaphor. Design, programming, refactoring, and debugging all have reasonable analogs in gardening, and even better is the mindset of "cultivating" a system over time. It's an organic metaphor, and that feels right to me.

    We do make software, but software isn't really like a bridge or an auto. The abstractness of software makes it more like a legal argument or a scientific theory. As a graduate student, I built models of arguments and theories and tried to understand how people create them. There's a lot of value in taking an engineering viewpoint on these tasks, but it doesn't always seem much like how people do them.

    Of course, the relationship between art, science, and engineering is a popular topic among reflective practitioners of all three. In just the last week I ran across an article by a physicist talking about superstition in scientific method and an article by an artist talking about the mundaneness of artistic craft. It seems that many seemingly different activities are less different in the doing than they seem at first glance.

    While I appreciate the gardening metaphor and think that it can help us understand something about what we do, I don't think it suffices as a model for how we make software. None of the metaphors I've heard of do. That's why I really like this quote from Richard Gabriel:

    Over the years I've tried to make the point that programming (even in its "hacking" form) is not precisely like anything else that people do, but is like everything that people do all at once: Programming is not engineering, but programmers do engineering, programming is not art, but programmers need to be artists, etc. The totality of the activity of programming is not like any one thing people do, but because people are people, we bring to bear all our ways of doing things - alone, in groups.

    We are just beginning to understand what it is to build software. Metaphors can both help and limit us in our discovery.


    Posted by Eugene Wallingford | Permalink | Categories: Software Development

    October 14, 2004 8:15 AM

    Isaac Newton, Failed Agile Software Developer

    Every once in a while I run across an article in a journal or trade magazine that reflects some misunderstandings about agile methods. Last July, I blogged about an article from a CS education magazine which asserted that using agile methods was unprofessional. (Presumably, then, so is teaching them as a viable alternative to traditional methods.)

    Yesterday, Steve Berczuk pointed the members of the XP discussion list to an article in the October issue of IEEE Computer called "Do Agile Methods Marginalize Problem Solvers?", by Victor Skowronski. (The article is available on-line to IEEE-CS members.) As Steve said, this column "sounds like it was written by someone who has read about agile methods but not used them."

    Skowronski's argument seems to be this:

    1. Excellent problem solvers often have personalities ill-suited for teamwork and, further, must often work in ways that do not match well with teamwork.

    2. Agile methodologies favor people with lesser technical skills and strong "people skills" over excellent problem solvers and others with technical skills whose people skills are subpar.

    3. Thus, agile methodologies are unsuitable for environments that require excellent problem solving skills and thus must attract people who have them.

    This, of course, means that agile methodologies are unsuitable for many (most?) software projects.

    The article uses two of history's great thinkers as examples: Isaac Newton and St. Thomas Aquinas. Apparently, Newton wasn't much of a team player, feuding with rivals, guarding his advances until publication, and preferring to work in isolation. Aquinas, though, was just quiet, a man living the life of the mind irrespective of his social circumstances.

    Would I really want a Newton on my team? Most software developers aren't writing software that will change the intellectual foundation of a discipline or even a company. They don't need to create new ideas of the depth and complexity of Newton's advances.

    Most software developers also don't get jobs for being pains in the behind.

    Would I want Aquinas on my team? Maybe. I can imagine having an excellent programmer be a valuable contributor to my team even though he is unable to pair effectively. I've never worked in such an environment, as my agile background is limited to teams that chose to use agile methods on their own, but I can imagine it. Maybe over time the loner becomes an effective pair; maybe instead the team adapts to the loner. It could work.

    Like so many articles of this sort, this one projects a lot of details into the description of agile methods that aren't really there. Perhaps this projection follows from never having tried agile methods, or maybe from an ideological bias. In any case, this article makes assumptions that demean agile proponents' professionalism and ethics.

    Forcing programmers into a communal workspace with no opportunity for either personal or professional privacy in the work place? Discouraging the writing of all documentation? Building software without adequate knowledge of one's task, tools, and domain? Please. Those aren't agile practices. They are just bad ones.

    A big part of the article discusses how the phases of problem solving fit with an agile approach, but it is largely beside the point. When an agile team needs to solve a thorny problem, agile developers can read books and seek other sources of information. They can take time away from the active production of code, if that's what's needed. The team can make reasonable decisions about how to advance its work.

    I did have some good thoughts as I read this piece, reminders to be agile:

    • Adapt to your personnel. Certainly. Agile processes aren't just about software; they also encourage us to be agile in how they work with people.

      That said, you should take care in assembling any software team, and an agile team is no exception. You may choose not to have a Newton or Aquinas on your team, if they don't fit. You might choose not to have lots of different kinds of people on my team.

    • Don't overlook developers who can contribute value but don't fit your stereotypes. This is a variant of the previous point. The article reminds us that a good problem solver who lacks people skills may seem less competent than a person who fits the agile mold. We certainly don't want to overlook potential contributors. We need to watch for opportunities to bring potential contributors onto the team and help them to contribute. They might even grow in the process, too.

    • Use methods appropriate to your project and environment. Well, certainly. Agile is as agile does. We need to mold our approach to the task at hand. But that doesn't mean throwing out things that we value as essential, like communication.

    Throughout this article, the author seems to imply that you can't find good problem solvers who are capable of working on an agile project. Hogwash. Not every person who excels at problem solving behaves as badly as Newton. I know a lot of smart people with great technical and problem-solving skills who use agile methods and like them. They wouldn't choose to develop software any other way. Furthermore, not all software teams need a problem solver as singular as Newton. Writing software is hard, but it is rarely as hard as inventing the calculus.

    One other claim caught my eye. This article defines the "best programmer" as the one with the most advanced problem solving skills. This is almost certainly the wrong answer. The best programmers are those people able to deliver high value to their customers for suitable cost. Problem solving is certainly an important component in being able to do that. It is essential that software developers be able to think deeply and to find solutions to thorny problems. But problem solving is not the only requirement for a good programmer; indeed, often it's not even the most important one.

    I know that this article is presented as an opinion piece, in a column that the editors of IEEE Computer hope will stir up foment. In that regard, I suppose, this piece succeeds. But still I wonder about the disinformation and misunderstanding of agile methods that cause people to write such stuff. I hope that Mr. Skowronski does better research before diving into one of those really hard problems that he needs to solve.


    Posted by Eugene Wallingford | Permalink | Categories: Software Development

    October 08, 2004 5:40 AM

    Refactoring Support for Scheme Programmers

    In a recent post, I mentioned that a group of my students is doing an XP-style project in Scheme. They have available a nice Scheme unit testing framework, equivalent to JUnit and tools available in many languages. Teams working in Java also have tool support for refactoring, particularly the open-source Eclipse and the academically-inexpensive IntelliJ IDEA. But googling and checking the refactoring tools page reveal no refactoring browser or IDE for Scheme. There are plenty of tools for Java, an increasing number for C#, and even one for Python... but none for Scheme. I am aware of a project by Simon Thompson and Claus Reinke on refactoring functional programs, but they are targeting the pure, statically-typed functional language Haskell.

    I think that the Scheme group most likely to produce a wonderful refactoring browser soon is the Dr. Scheme group, but I don't think they have done anything in this direction yet. They do have a unit testing framework integrated right into their IDE, though.

    One of my current R&D goals is to create a simple refactoring browser for Scheme. I started a project on Scheme-processing tools last spring, and refactoring is the first big tool I want to produce. Right now, I'm working in Java, because of its platform-independent support for GUI code and because it is most accessible to my students at the university. Eventually, I could see migrating to Dr. Scheme, and writing the tools and browser in Scheme itself.

    If you are a a student who is interested in working on this project, let me know. If you know of any other projects targeting refactoring support for Scheme programmers, let me know.


    Posted by Eugene Wallingford | Permalink | Categories: Software Development

    October 07, 2004 5:30 PM

    Agile Software Development in the Large

    I just received my copy of Jutta Eckstein's new book, Agile Software Development in the Large: Diving into the Deep in the mail yesterday. (Thanks, Jutta!) This book addresses one of the persistent myths about agile methodologies: that they only work for small teams. Jutta is a consultant with many years' experience in software development, and she has written this book to document practices that have worked for large teams building software in an agile way. And when she says 'large', she means 'large', projects with up to a 1,000 developers.

    Most books on agile software development either theorize or talk about the use of agile methods on a smaller scale. That is natural, as many of the pioneers are writing about their experiences using agile ideas in their own smaller organizations. Unfortunately, this has left the agile folks at a disadvantage when asked, "But does it scale?" My answer to this question has always had to be "I don't know for certain", because I've never seen agile methods applied in large, traditional software houses. (I always follow up with theorizing about how it could or should scale, but such theories don't encourage much confidence in a person who has to bear the risk of potential failure if it doesn't.)

    Just from my first skim of the book, I see many things that I like. Perhaps best is that this book presents practical guidelines we can all follow. It illustrates the guidelines with stories of real projects, but Jutta has done some serious thinking to distill wisdom from her decade of experience with the agile methods. I also like that the book isn't specific to XP or Scrum or any other particular agile approach. It deals instead with the values and principles that are common to all of these. As a result, the advice we receive here should be useful no matter how we tailor a particular approach to our organizations.

    So, I am quite excited to read Jutta's book this weekend. She can teach me something about agile software development that lies outside my experience. I know of Jutta's work in the OOP and patterns communities, and I have come to respect her insight and pragmatism. This book should become a staple on my agile bookshelf.


    Posted by Eugene Wallingford | Permalink | Categories: Software Development

    October 04, 2004 5:44 PM

    Pleasant Surprises

    My Agile Software Development class is doing a big course project. The students are creating the beginnings of a content management system for me, with an initial eye toward me writing content for a book and their program generating a web site for the content. I don't know how far we will get this semester, but that is part of the fun of the project.

    Most of our students have spent a year learning Java and a semester learning Ada, so those tend to be the languages in which they want to program. I expected most folks to want to work in Java, given all of the tools that support agile development in that language, starting with JUnit but extending to Eclipse, Ant, and others. (Actually, I knew that a few would probably want to program in C, but tool support for agile approaches in C is still weak. Go, Ale, go!)

    Imagine my surprise when a four-person team asked me if they could use Scheme. They had all learned Scheme in my Programming Languages course, so this wasn't an impossible request. But only rarely does Scheme attract a student's fancy in my course... The language is just so different from what they know that, even if they come to appreciate its power, they usually don't grok how they might use it as a development language on a "real" project. These students had all done well in the Scheme part of Programming Languages, but they hadn't expressed any deep love for the language at the time.

    So my initial reaction was, "Are you jerking my chain?" But they insisted they weren't, that Scheme seemed like the right tool for the job at hand: transforming data from one form to another, with flexible parsing underneath. So I let out a little bit more chain and said, "Well, you'll have to get a unit testing framework so that you can write your tests first..." I had mentioned SchemeUnit in passing earlier in the course but hadn't told them just how nice unit testing can be in a dynamically typed and highly flexible language like Scheme. They said, "No problem."

    They did it. The team submitted the build of its first iteration last Friday. They have three dozen or so tests and three of four domain modules. The code looks good. We'll see what happens by the end of the first "official" release of their code -- two more iterations to go -- but I've graduated from cynical skepticism to guarded optimism.

    This is enough to restore my faith in humanity. To quote ranch owner Clay Stone from one of my favorite movies, City Slickers, I'm as happy as a puppy with two peters.


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

    October 03, 2004 5:00 PM

    Duplication in Many Forms

    We all know that, all other things being equal, duplication in a program is bad. The Pragmatic Programmer uses the phrase DRY -- "Don't Repeat Yourself" -- to capture the essence of this idea. Unchecked, duplication creates a maintenance nightmare, because changes to the system may be needed in several, hard to find places.

    When programming test-first, duplication is a natural part of the development process. First, we craft a test for a requirement, and then we do the simplest thing possible to make the test pass. That simplest thing often involves duplicating some other piece of code, with perhaps a few tweaks that distinguish the new case from the existing one. Test-first development doesn't leave the duplication unchecked, though, because it calls for us to refactor our code as soon as the code for a test passes.

    What sort of duplication should we look for when refactoring code, whether as a part of TDD, as part of taming a legacy system, or as part of improving our non-TDD system?

    Duplication can occur in many guises, not all of which are immediately obvious when examining a body of code.

    The simplest form of duplication is when two pieces of code look the same. Such textual duplication results from copy and paste, but it can also occur when solving related problems independently. When we duplicate text via copy and paste, we usually know to eliminate the duplication in the upcoming refactoring phase. Even when we generate it independently, it's easy enough to recognize as we move around our code base. Common refactorings such as factoring out a method or superclass address textual duplication.

    A particular sort of textual duplication arises in how we sometimes name things. Consider this piece of Java code, based on a thread on the refactoring discussion list:

    sendMessageToServer( Message m, Server s )

    There's a not-so-subtle duplication in the name of the method and its arguments. I like explicit names, to the point of using longer names than most folks like to type or read, but this example repeats the intent of the method in the method name sendMessageToServer and the argument types Message and Server. The duplication rises to another level when used in this too-common way:

          Message message = ...;
          Server  server  = ...;
          ...
          sendMessageToServer( message, server );
    

    That's triplication, not duplication! Let your language do some work for you. And you don't need to work in a statically-typed language to see how good names can eliminate such repetition. A typical Smalltalk method signature for the above would probably read:

          send: aMessage to: aServer
    

    We can eliminate this sort of name duplication by choosing better names. :-) Name methods for their actions, and let the names of argument objects participate in the readability of an statement.

    A related form of duplication occurs when two pieces of code behave alike. We can call this functional duplication. Sometimes functional duplication begins as textual duplication, but it can happen quite innocently as programmers working on different parts of a system reinvent one another's solutions to common problems. When two methods or two classes do the same thing, we run into the same maintenance problem as in textual duplication. When requirements change, one of the methods or classes may be modified or enhanced, leaving some part of the system using an older version.

    Functional duplication is hard to find, because the code may not jump out at you. One of the less-mentioned benefits of small methods and small classes is that it's harder for functional duplication to hide in complex code. If you see code that does the same thing as another piece of code, you're more likely to see it in simpler code. XP's encouragement that all programmers work on all parts of the system over time, through promiscuous pairing and non-exclusive attachment to particular sub-systems also helps us avoid this problem, as we are more likely to come into contact with all of the system's functionality sooner or later. Once identified, we can eliminate functional duplication using many of the same factoring techniques as we use on textual duplication. But we may also need to redesign some of our interfaces when different functionality goes by different names in the system.

    Dave Astels points out another kind of duplication in his article on bad code: temporal duplication, when work is repeated unnecessarily in a program. I see this sort of duplication when both client code and server code perform safety checks on the values of variables, say, to verify a pre- or post-condition. But it can happen in other ways, too. For example, student code often asks a collection if it contains an entry with a particular key, and when the collection says 'yes' it asks for the entry. This may involve searching the underlying collection instance variable twice. Temporal duplication is harder to find, because it requires a deeper feel for what the code is doing.

    One way to eliminate temporal duplication is to decide who is responsible for an invariant condition and then having only that object enforce it. Another is to rethink the interface of an object -- why ask the collection if it contains the key; why not just ask for the desired entry and behave appropriately when it can't find it? A third way is to cache the result of the first effort and then return the value immediately upon future requests. Choosing which of these techniques to use is a matter of balancing different forces. Someone should write some patterns...

    There are some other forms of duplication that show up as a result of how we design our code. Kevin Rutherford wrote an article or two on how many if statements duplicate knowledge held elsewhere in the system. This is a sort of epistemological duplication that lies at the heart of good system design. In object-oriented programming, we don't need to use an if statement to recover what the system knows or used to know. At the moment the system knows something about its future behavior, it can create an object that has that behavior. Joe Bergin and I have been encouraging this as a way for students and instructors to design programs that make better use of polymorphic dispatch than explicit selection. The advantage of polymorphic dispatch over if statements is, of course, that we can customize a program's behavior by plugging a new kind of object into the system, rather than editing the program code to address another case in the if statement. And, where there is one such if, there tends to be more than one, and we end up with a form of textual duplication if only in the structure of the choices being made!

    I like this quote from the Rutherford article mentioned above as a concrete criterion for recognizing epistemological duplication in choices:

    Therefore it seems to me that there are two kinds of conditional statement in a code base: The first kind tests an aspect of the running system's external environment (did the user push that button? does the database hold that value? does that file exist?). And the second kind tests something that some other part of the system already knows. Let's ban the second kind...

    Duplication in all its forms can come back to hurt a programmer in the long run. I think that one of reasons we feel so good when we read the code of the masters is that even the less obvious forms of duplication are nowhere to be found. We may not recognize this reason, but it's there. Look for these kinds of duplication the next time a piece of code makes you say "Ahh!" or "Ugh." You may be surprised by what you find -- and what you don't. Then think about these kinds of duplication the next time you are refactoring your code. You will surprise yourself by the opportunities you have to improve your program.


    Posted by Eugene Wallingford | Permalink | Categories: Software Development

    September 28, 2004 5:08 PM

    The Sweet Spot of Programming

    A great line from About Kim:

    I suppose the sign of a sweet-spot language is when you naturally fall into using it for writing pseudocode.

    How many of the languages you program in hit the sweet spot?


    Posted by Eugene Wallingford | Permalink | Categories: Software Development

    September 24, 2004 11:12 AM

    Why Not Program Test-First?

    "If you can't write a test for the code you are about to write, then you shouldn't even be thinking about writing the code."

    And if you can, why not write it now? Then you will know for certain that you can, and that you aren't just fooling yourself.

    Good programmers sometimes ask me why they should bother. They already write good code. Do such programmers really need the extra discipline of TDD? Perhaps not. But good programmers are people, too, and so are subject to the same tendencies as anyone else. When the pressure is on, or when they are surprised by a new requirement, they are all too prone to tell themselves that they really do understand.

    There is another, perhaps better, reason for good programmers to practice TDD: good programmers often work as part of a team. And as a member of a team, they depend on the quality of the code produced by the entire team, not just themselves. A good programmer can benefit from having his teammates practice the discipline. In this way, even weaker members of the team will develop better code, which benefits everyone. The good programmers will want test-first to be a team discipline, so everyone practices it.

    If writing tests first is something you can do anyway, the real question becomes: Why not?


    Posted by Eugene Wallingford | Permalink | Categories: Software Development

    September 22, 2004 2:24 PM

    No Comment?

    I just read a long rant by a student who is studying Paul Graham's ANSI Common Lisp. He was trying to understand an especially Lispy piece of code and having troubles. At the top of the code file he submitted, he included a comment over a page long talking about code readability, comments, and mental sanity. I enjoyed it very much.

    Many folks who have studied "advanced" Scheme or Lisp code know what he is talking about. I use the scare quotes because, while students often characterize the code this way, the code doesn't really have to be all that advanced to create this kind of disorientation. It doesn't have to be Scheme or Lisp, for that matter; I had a similar experience when I studied Haskell programs. It's more about programming style and familiarity than language. (Perl may be an exception. Does anyone really understand that stuff? :-)

    Functional languages tend to cause the kind of disorientation that my student felt, because we don't teach or learn functional programming very much or very well at most schools. Almost everyone who comes into contact with functional programming does so from a position of weakness. That's too bad, because functional programming can be powerful and beautiful, and as time passes we see more and more elements from functional languages migrating into popular languages like Java, C##, and Python. I'm glad that the TeachScheme! folks are building tools and developing techniques for teaching this stuff better.

    That's really just a prelude to what triggered my writing on this topic, which was the part of the student's rant that dealt with comments. He felt that, if Graham had commented the function in question, understanding it would have been easier. But as I read further into the rant, I found that much of the student's misunderstanding arose from his not understanding graphs and graph search as well as he might.

    Graham could certainly have explained more about graphs and breadth-first search, but his function isn't a textbook; it's a Lisp function. He could have added a comment with a pointer to explanatory material, but I suspect that Graham assumed his readers would already know certain CS basics. He is trying to teach a certain audience how to program in Lisp effectively, and perhaps something more general about programming. But teaching data structures and algorithms isn't one of his goals.

    Commenting code is a perennial topic of debate among programmers, students, and instructors. How much is too little, enough, too much? Brian Marick wrote a nice little piece that points out something folks seem to forget occasionally:

    But code can only ever be self-explanatory with respect to an expected reader.

    When writing code, you have to know your expected audience, but you also have to know something about other potential readers. Then you have to make some hard decisions about how to write your code and comments in light of all that.

    I don't expect that my students put a lot of comments in the code they write for class. Their expected audience consists of primarily me, with themselves and their fellow students as other potential readers. I don't need them to explain to me how a for loop works, or what an assignment statement does. I much prefer that they choose variable names and organize their code in ways that make their intention clear than that they add gratuitous comments to the code.

    On the other hand, I sometimes put comments in my code that reflect the fact that I am teaching students about some idea. If my code example is for CS I, then I may well comment a for loop with explanatory material. For CS II, I may add comments that explain the role played by a class in the Decorator pattern. Even so, I sometimes don't add comments of this sort, because the code is read as a part of lecture notes that explain the ideas behind the code. Maybe I should be more conscientious of the fact that many students will read the code of the context of the lecture -- or not even read the lecture at all!

    As I responded to some of my student's rant, my mind shifted to the old questions: Just when are comments most useful? When should programmers comment their code, and with what sort of comment? Let's assume that the programmer is writing for readers of roughly her own level of skill and understanding.

    I surfed on over to a wiki page I first read long ago and have always loved, Method Commenting. Ward Cunningham started that page with some patterns of code and comments to summarize a discussion of the topic. These patterns resonate with me. The basic theme is that people read code, and you should write for them.

    Code should reveal the intentions of the programmer, using names and method decomposition that communicate purpose. For example, one of the things my student disliked in the function he was studying was its lack of data abstraction -- the function uses cars and cars all over the place, which are implementation details. The code would read better with Syntax Procedures for the abstract path operations they implement.

    That said, programmers have to learn how to think like the machine. Programs aren't novels; they aren't even how-to manuals. A reader can't expect to have normal computational behavior explained in comments. What counts as normal depends on many things, including at least the programming style and language.

    Here is a situation that calls for a comment: Sometimes, you have to write code for the machine, for example, when an optimization is required. This code may mislead the reader. So, give the reader a clear warning in order to avert a misunderstanding.

    Here's another: Sometimes, you can take advantage of a given specification, say, a limit on the size of a collection, and implement an especially efficient algorithm. But the spec may change, and the code may then become a liability. So, fence off your code by documenting in a comment the constraint and its role on your implementation. (These days, I find that my unit tests serve this purpose better, and they are code!)

    There are some other situations where I use a comment, but they usually involve process. Sometimes, I have to leave a piece of code undone. A comment can help me know what is left to be done. Other times, I have a great idea that I don't have time to explore at the moment, and a comment can help me remember the idea. But I worry about both of these kinds of comments, because they tend to have a short lifespan of utility. If I don't get back to the same code soon, the comment on my great idea may not mean much to me when I get back to it. Or, worse, I don't see the comment until after it's too late. I usually prefer to make a note to myself in some other form for such things.

    When else is a comment better than (better) code?


    Posted by Eugene Wallingford | Permalink | Categories: Software Development

    September 20, 2004 8:29 AM

    I Feel Good. I Feel Great. I Feel Wonderful.

    Mark Jacobson, a colleague of mine, is a big fan of the movie Ghostbusters. Now, I like that movie, too... I remember the first time I saw it, when my brother and I came home and replayed the whole movie all afternoon, and I've seen it many times since. But Mark is a big fan. He believes that Ghostbusters can help students learn to be better students. You can see his many Ghostbusters-related links on his homepage.

    I am a huge Bill Murray fan. Last night, I watched one of my other favorites from his filmography, What About Bob? This movie is pure goofiness, unlike the high art of Ghostbusters, but I enjoy it. I must have been in a goofy mood this weekend, because I began to notice all the things that What About Bob? can teach us about agile software development. Humor me.

    First, a little about the movie. Bob Wiley (Murray) is a mess, a multiphobic who can barely even leave his apartment. He's also so obsessive about his therapists that they keep passing him on. At the beginning of the movie, Bob's current therapist leaves his practice in order to get away from. Bob is referred to Dr. Leo Marvin, a successful and self-absorbed psychiatrist played to perfection by Richard Dreyfuss. Leo is about to go on vacation after the publication of his blockbuster self-help book Baby Steps. Bob manages to wheedle an appointment on that fateful last morning, making his first sparks with Leo and receiving a retail-price copy of Baby Steps.

    It took me a long time to realize that Bob is a software developer. He's paralyzed by change, fears interacting with people (clients), and can't make progress toward his goals. He also isn't good at pairing. He was married once, but that ended quickly because, as he tells Leo in their first session together, there are two kinds of people in the world: people who like Neil Diamond, and those who don't. And people of different kinds can't work together.

    The first thing he learns from Leo is take baby steps. Trying to take on all of the world's pressures at once would paralyze anyone. Set a small goal, take the actions that achieve just that goal, and then reassess the situation. (That's test-first development, Do the Simplest Thing, and small releases.)

    One thing that Bob already seems to understand is the need for continuous feedback. That's what he seeks from his therapists -- and also what keeps driving them away. He needs too much attention, because he is caught up the backwards pathology of modern business. He seeks feedback not from the world, which is where he takes his actions, but from his therapist, who represents his manager. He wants someone else to tell him what to do, and how to feel, and how to live. A professional must take responsibility for his own actions and feelings and life. That's one of the things that folks like Jerry Weinberg and Pragmatic Programmers have emphasized so often to software people for so many years.

    We also see that Leo needs feedback, too. When planning for his live interview on Good Morning, America, he asks his family to help him choose what to wear and where to stand, but they are so busy with Bob that they don't pay him enough attention. "I need feedback, people!" he screams in a moment of raw emotion. And he does. The ever presence of the dysfunctional Bob accentuates Leo's own egotistic tendencies and pushes him to cry out for help.

    Another lesson Bob learns from Leo comes in the form of a prescription -- not for more medication, with which Bob seems to have far too much experience, but to "Take a Vacation". This is a veiled reference to the agile principle of sustainable pace. In addition to taking steps that are too big, Bob spends every waking moment, and apparently many of his sleeping ones, focused on his problems. Such obsession will burn a person out, and only taking regular breaks can cure the obsession. Bob isn't cured when he decides to take a literal vacation from his problems, but his vacation is another step on the road to recovery. Unfortunately for Leo, Bob decides to vacation in Lake Winnipisaukee along with the Marvin family, which is another step for Leo toward collapse.

    I'm still working on the role played by Leo's family in our little morality play. Leo's wife, Fay, and children Anna and Siggy take to Bob quickly, finding his attempts to put a happy face on the world refreshing after all the years of seriousness and isolation from Leo. It is in his interactions with these gentle, loving people that Bob begins to grow out of his sarcophagus, putting the lessons of baby steps and vacations into practice. Perhaps they somehow symbolize clients, though most software developers wouldn't characterize all of their clients as gentle and loving. However, it is in interaction with these folks that Bob learns that he does not have to shoulder all of his burdens alone. (As an aside, Anna's Kathryn Erbe can have a role in my stories any day!)

    This leads us to the central question remaining: Who is Dr. Leo Marvin? The agile coach, of course. He teaches Bob to overcome his fears, to accept the world as it is, and to embrace change. Unlike with Bob, I felt an overwhelming urge to identify Leo with a real person in the community. Kent Beck? Uncle Bob Martin? Finally, near the end of the movie, we have our answer. Bob Wiley is ultimately cured by Leo's latest invention, the not-so-tongue-in-cheek Death Therapy. Through a single attempt at Death Therapy, Bob learns to untie the self-made knots that bind him and to take command of his life. He even becomes able to pair again, marrying Leo's sister, Leo.

    And so we learn that the model for Leo must be Ron Jeffries, who recently so eloquently described the role that Death Therapy might play in reversing the fortunes of a software industry that so often binds itself up with long-range plans, unnecessary separation of tasks, and fear of change.

    Shh. Don't tell Ron any of this, though. Leo goes crazy at the end of What About Bob?, unable to shake Bob's obsessions. But Bob is cured!

    That's all the Metaphor I can manage today. Thankyouverymuch.

    Oh, and if you are one of my students, don't expect this to show up in one of my classes. As much as I'd love to watch What About Bob? again with you all in class, I don't quite have the personality to carry this sort of thing off live. Then again, you never know...


    Posted by Eugene Wallingford | Permalink | Categories: Software Development

    September 16, 2004 4:01 PM

    Paying Attention to the Details

    At PLoP last week Gerard Meszaros said something that caught my ear:

    risk = probability X consequence

    Why waste energy minimizing a risk whose consequence is too low to be worth the effort?

    This idea came up later at the conference when Ward talked about the convention-busting assumption of wiki, but it is of course a central tenet in the agile methods. Too often, when faced with an undesirable potential result, we focus too quickly on the event's likelihood, or on its effects. But risk arises in the interplay between the two, not in either factor alone. If an event is likely to happen but has only a small negative effect, or if it has a major effect but is unlikely to occur, then our risk is mitigated by the second factor. Recognizing this can help us avoid the pitfall of running from a potential event for the wrong reasons.

    Recognizing this relationship can also help us to take control of the problem. In XP and the other agile methods, we accept that change is highly likely, so we work to minimize the consequence of change. We do that by maintaining a comprehensive suite of tests to help us verify that changes to the system don't break something unexpectedly; and, when they do, we use the tests to find and fix the problem spots. We minimize the consequence of change by using refactoring tools that help us to change the structure of our programs when design requirements call for something different. We minimize the consequence of change by working on short iterations, continuously integrating our code, and releasing versions frequently, because these disciplines ensure that we get feedback from our tools and client frequently.

    Learning to pay attention to all the variables in a situation is more general than just assessing risk. In a recent message to the XP mailing list, Kent Beck said that he tries to help his customers to think in terms of return, not just value or cost:

    I have another goal for early estimation, which is to encourage the business-decision-makers to focus on return instead of just value. If the choice is between the Yugo and the Ferrari, I'll take the Ferrari every time. If I have $6000 and I know the price of the two cars, my thinking is more realistic.

    A system's value is a function of many variables, including its features, its cost, and the environment in which it must operate.

    We can become more accurate, more efficient decision makers by paying attention to what really matters, and not being distracted by our biases and initial reactions. Often, these biases were learned in other times, other environments. Fortunately, I think that this is something that we can learn to do, by consciously developing new habits of thought. It takes discipline and patience to form new habits, but the payoff is often worth the effort.


    Posted by Eugene Wallingford | Permalink | Categories: General, Software Development

    September 12, 2004 10:38 AM

    Myth and Patterns

    Yesterday was an unusual day for PLoP: we didn't have any writers workshops. This year, we squeezed all of the paper sessions into the first two days of the conference, setting aside Saturday for two extended sessions by Norm Kerth and Ward Cunningham. Among their many accomplishments, Norm and Ward are two of the founding fathers of the software patterns community, and their talks commemorated the first PLoP conference ten years ago.

    Norm led a discussion on myths. I like two of the definitions offered. One person defined a myth as "a story that is so true you can't use the facts to explain it." Richard Gabriel's definition turned on a myth's effects: A myth is "a story capable of generating stories in every person who hears it."

    Many folks might think that a discussion of myth is out of place at a conference on software development, but this session was spot on at PLoP for two reasons. First, this session celebrated the conference's tenth anniversary, and so stories about its founders and founding were on everyone's mind. The conference's opening session focused on the Genesis Myth of the patterns community, sprinkling facts among the essential truths. Norm's session this morning was more about the Hero's Journey myth, told in various forms by all cultures.

    More important is the second reason. Science is itself a myth. It is a set of stories that purport to explain how and why the world is. We hold some of these stories true (the Greek theory of atoms) until a better story comes along (Newtonian physics, relativity, quantum mechanics, string theory...).

    Software folks have their myths, too. Software engineering is a comprehensive one. Extreme programming is a myth, one of a complex set of myths that we call agile software development.

    Patterns are themselves myths. They are stories we tell about the successful systems we see around us in the world. They have a narrative form and expected components. We use them to help others understand what we think we understand, and we write them to help ourselves understand.

    I don't worry that these ideas are "just" stories that we tell. They embody our current understanding of the world. We try to use more scientific methods than our forbears in constructing and refining our stories, but we must always keep in mind that they are just that -- stories -- and that we can them. One of the beauties of XP is that Kent Beck and his colleagues chose to create a story with such a challenging premise and the promise of something different. Because it is agile, it is made to be shaped to its environment, retold in as many different forms as there are tellers, as we all work together to find deeper truths about how to build better software better.

    Deep truths often lie inside stories that are themselves not strictly factual. A classicist who now does software at IBM reminded us of this during the session. I love PLoP.

    "... as we all work together to find deeper truths ..." is a great segue to Ward's afternoon session, but because I didn't post this last night I will have to wait to tell that story after I get home from the conference.


    Posted by Eugene Wallingford | Permalink | Categories: Software Development

    September 03, 2004 4:45 PM

    Can You Turn It In Now?

    Conventional wisdom is that many software projects are completed late and over budget. I don't know whether this is true, or to what extent, but few dispute the claim. Within the software engineering community, this assertion is used as motivation to develop more rigorous methods for building software and managing the process. In the popular press, it is viewed with much head shaking and a bit of disdain. Yet people must continue to buy software.

    We face a similar issue in academia. Many professors accept late work for a few days after an assignment is due. Sometimes they assess a penalty, such as 10% of the available points per day. But compassion usually dictates some degree of flexibility with our young charges.

    My grading policy has always been not to accept late work. I tell students to submit their best available work at the time the assignment is due. I also place a lower bound on the acceptable quality of a submission: If a program doesn't compile, or compiles but blows up horribly when run, then the resulting grade will be quite low. I tell students that, all other things being equal, a compilable, runnable, yet incomplete program is more valuable than a program that doesn't compile or run. It's hard for me to have much confidence in what a student knows or has created when even the compiler balks.

    I'm reasonable enough to make exceptions when events warrant them. Sometimes, extenuating circumstances interfere with a student's opportunity to do the assigned work in a timely fashion. Sometimes a reasonably good, nearly complete program causes an exception in an unusual situation that the student doesn't yet understand. But for the most part, the policy stands. Students long ago stopped questioning this rule of mine, perhaps accepting it as one of my personal quirks. But when deadlines approach, someone will usually ask for a break because with just a little more time...

    Of course, I also encourage students to do short iterations and generate many "small releases" as they write programs. If they work systematically, then they can always be in the position of having a compilable, runnable -- if incomplete -- program to submit at every point in a project. I demonstrate this behavior in class, both in project retrospectives and in my own work at the computer. I don't know how many actually program this way themselves.

    These thoughts came to mind earlier this week when I saw a message from Ron Jeffries to the XP mailing list, which appeared in expanded form in his blog as Good Day to Die. Ron considers the problem of late software delivery in industry and wonders,

    What if the rule was this?

    On the day and dollar specified in the plan, the project will terminate. Whatever it has most recently shipped, if it has shipped anything, will be assessed to decide whether the project was successful or not.

    Does that sound familiar? His answer sounds familiar, too. If you program in the way that the so-called agile methods people suggest, this won't be a problem. You will always have a working deliverable to ship. And, because you will have worked with your client to choose which requirements to implement first, the system you ship should be the best you could offer the client on that day. That is fair value for the time spent on the project.

    Maybe my grading policy can help students learn to produce software that achieves this much, whatever its lifespan turns out to be.


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

    August 27, 2004 2:18 PM

    By Any Other Name ... Not!

    Everyone knows that using good names in code is essential. What more is there to say? Apparently, plenty. I've encountered discussions of good and bad names several times in the last few weeks.

    Not too surprisingly, the topic of names came up during the first week of my introductory OOP course. I gave my students a program to read, one that is larger than they've read in preceding courses and that uses Java classes they've never used. We talked about how good names can make a program understandable even to readers who don't know the details of how an object works. The method names in a class such as java.util.Hashtable are clear enough that, along with the context in which they were used, students could understand the class that uses them.

    Often, issues that involve names are really about something bigger. Consider these:

    • Jason Marshall writes about a design anti-pattern that he calls Implied Structure. Sometimes, developers need to create an object with a descriptive name in order to communicate knowledge they possess but that their program doesn't express. The new object, even if it is light on behavior, captures a valuable domain abstraction. The name communicates the abstraction to readers of the code, and it also allows the compiler to enforce meaningful values for variables.

    • Nat Pryce recently wrote about methods that take arguments which change the meaning of the method. In particular, Nat is concerned with arguments that negate the method's meaning, such as:

      void assertButtonIsEnabled(String buttonName, boolean isEnabled)

      When a client passes false as the second argument with this message, the result is that the button is disabled. Such code is almost impossible to follow, because you have to pay attention to the guilty argument in order to get even a high-level understanding of the code.

      Avoiding this situation is relatively easy. Create a second method with a name that says what the method means:

      void assertButtonIsEnabled(String buttonName)
      void assertButtonIsDisabled(String buttonName)

      Not only is Nat spot on with his analysis, but he has come up with a wonderfully evocative name for this anti-pattern, at least for those of us of a certain age: the Wayne's World Method. This name may be too specific in time and culture to have a long life, but I just love it.

    • Finally, OOPSLA 2004 has been much on my mind lately, with all my work on the Educators Symposium. I always look forward to OOPSLA's invited talks and keynote addresses, and this year one in particular has caught my eye, Ward Cunningham's Objects, Patterns, Wiki and XP: All Systems of Names. I am a big fan of Ward and his work. He seems always to be in the vanguard of what everyone will thinking about in a few years. According to the promotional buzz, Ward's talk will "unravel" his experience "building tools for the not quite tangible".

      I'm not sure exactly what Ward will talk about, and I can't wait to find out. But the title hints that he will follow the thread of names through several of his contributions to our industry. Just think about the role names play in connecting the tissue of a pattern language, the fabric of ideas that is a wiki -- and the domain model that comprises an object-oriented program. And perhaps names play a more central role? I look forward to Vancouver.

    Important ideas have a depth that we can explore in thousands of ways, never quite the same. Names are one of them.


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

    August 23, 2004 4:29 PM

    Technology, Speed, and Language

    Ryan Dixon pointed out an interesting connection between technology, speed, and language in response to one of my recent posts. Recall that Clive Stephenson had blogged on how typing changes how we write, because it lets us put more material on the page faster than writing by hand. In my recent entry, I talked about how a similar 'speed-up' technology -- agile development -- affects how we write programs and how this perhaps should affect how we teach programming.

    In response, Ryan sent me this quote by Paul Graham, from his wonderful On Lisp:

    Imagine the kind of conversation you would have with someone so far away that there was a transmission delay of one minute. Now imagine speaking to someone in the next room. You wouldn't just have the same conversation faster, you would have a different kind of conversation. In Lisp, developing software is like speaking face-to-face. You can test code as you're writing it. And instant turnaround has just as dramatic an effect on development as it does on conversation. You don't just write the same program faster; you write a different kind of program.

    This is an important insight: you would have a different kind of conversation. Notice the how the ideas of testing and continuous feedback play into Graham's comment. And notice that the synergy between the two leads not just to a difference in degree but a difference in kind. Graham obviously thinks that the change is an improvement. I do, too.

    I think this notion underlies the benefits of having empowering technology in your hands. It's why writers are usually better off by getting lots of material down on paper quickly: the act of making thoughts concrete in words changes the act of writing, and it gives the writer something real with which to work. It's why an agile development style can lead to good programs -- better programs!? -- even without big design upfront: the act of writing small tests and small functional bits of code change the act of programming. They also give programmers something concrete with which to work, rather than fuzzy requirements and the design abstractions they build in their head. Programmers learn from the growing program, and they can feed this learning back into the next code they write.

    Graham speaks specifically of Lisp, but I think he'd agree that other languages offer a similar experience. Smalltalk is one. Interactivity plays a big part in the experience, though there's also something about the kind of language one programs in buried in there, too. Some languages facilitate this style of programming more than others. Lisp and Smalltalk, with their "everything is customizable" designs, do just that.

    I love how seemingly little ideas can flow together to create something much bigger...


    Posted by Eugene Wallingford | Permalink | Categories: Software Development

    August 19, 2004 1:50 PM

    Multiple Iterations and Care for Programs

    Fall semester is in the air. The students are beginning to arrive. As I prepare for my courses, I've been thinking about some issues at the intersection of agile development, programming style, thinking ahead, cognitive styles, and technology.

    Many computer science faculty pine for the good old days when students had to plan their programs with greater care. To this way of thinking, when students had to punch programs on cards and submit them for batch processing at the computer center, they had to really care about the quality of their code -- think through their approach ahead of time, write the code out by hand, and carefully desk-check it for correctness and typos. Then came the era of interactive computing at the university -- when I was an undergrad at Ball State, this era began with the wide availability of DEC Vax terminals -- and students no longer had to be careful. Professors love to tell stories from those Vax days of receiving student submissions that were Version 132 of the program. This meant that the student had saved the program 132 times and presumably compiled and run the program that many times as well, or close to it. What could be a worse sign of student attention to planning ahead, to getting their programs right before typing?

    I've never held this view in the extreme, but I used to lament the general phenomenon. But my view is now mixed, at best, and moving toward a more agile perspective. Under what conditions would I want my students to save, compile, and run a program 142 times?

    In agile development, we encourage taking small steps, getting frequent feedback from the program itself, and letting a program evolve in response to the requirements we implement. In test-driven development, we explicitly call for compiling and running a program even when we expect a failure -- and then adding functionality to the program to make the test pass.

    If my students program this way, then they will necessarily end up with many, many saves and compiles. But that would be a good thing, and at every step along the way they would have a program that deserves partial credit for a correct but incomplete solution.

    In order for this approach to be desirable, though, students need to do more than just code, compile, and run. They will need to add individual features to their programs in a thoughtful, disciplined way. They will need to do some testing at each step, to ensure that the new feature works and that all older features still work. They will need to continuously re-work the design of their program -- refactor! -- as the design of the program evolves. And all of these take time. Not the frenzied iterations of a student whose program is due tomorrow morning, but the intentional iterations of a programmer in control.

    To me, this is the biggest difficulty in getting students to program in an agile style. Students are so used to procrastinating, to doing triage on their to-do lists in order to get the most urgent project done first. Unfortunately, many also give higher priority to non-school activities all too often. I am always on the look-out for new ways to help students see how important time is in creating good programs, whether by planning carefully ahead or by going through many planned iterations. Please share any ideas you have.

    So, many iterations isn't a problem in itself, but rather a style in which those iterations are the result of the seemingly random modify-and-compile approach that many students seem to fall into when a program gets tough. Part of our job as teachers is helping students learn discipline in attacking a problem -- more so than teaching them any particular discipline itself.

    Why the mention of cognitive styles above? A blog entry by Clive Stephenson brought this topic to the front of my mind a few weeks ago, and it wasn't about programming at all, but about writing more generally:

    ... Is there any difference between our cognitive styles when we write longhand, versus typing on a keyboard?

    Since I type about 70 words per minute, I can type practically as fast as I can compose sentences in my head. So does the much-slower pace of handwriting actually create a different way not just of writing, but of thinking? Does the buffer buildup between my brain and my arm affect things?

    What I mean is this: When I'm typing, because I can generate text so fast, I'll toss lots of stuff out on the page -- and then quickly edit or change it. But when I'm writing by hand, because it's so much slower I'll try to compose the sentence in my head before trying to write it. With a keyboard, I sort of offload some of my mental-sorting onto the page, where I can look at the words I've written, meditate on them, and manipulate them. With writing, that manipulation happens before the output. Clearly this would lead to some cognitive difference between the two modes ... but I can't quite figure out what it would be.

    Changes in technology have made it easier for us to get ideas out of our heads and onto paper, or into a computer file. That's true of good ideas and bad, well-formed and inchoate. For many writers, this is a *good* thing, because it allows them to get over the fear of writing by getting something down. That's one of the things I like about having my students use more agile techniques to program: Many students in introductory courses are intimidated by the problems they face, are afraid of not being able to get the Right Answer. But if they approach the problem with a series of small steps, perhaps each small step will seem doable. After a few small steps, they will find themselves well on the way to creating a complete program. (This was also one of my early motivations for structuring my courses around patterns -- reducing fear.)

    Used inappropriately, the technology is simply a way to do a poor job faster. For people whose cognitive style is more attuned to up-front planning, newer technologies can be a trap that draws them away from the way they work best.

    In retrospect, a large number of compiles may be a bad sign, if they were done for the wrong reason. Multiple iterations is not the issue; the process that leads to them is. With a disciplined approach, 142 compiles is the agile way!


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

    August 17, 2004 2:07 PM

    August 13 -- My Talk on Test-Driven Development

    On the last day of SugarLoafPLoP 2004, I gave my test-driven development tutorial as the last event on the main program, just before the closing ceremony. I was pretty tired but brought as much energy as I could to it. The audience was tired, too, and it showed on their faces, but most folks were attentive and a couple asked interesting questions.

    One person asked about the role of traditional testing skills, such as finding equivalence classes on inputs, in TDD. These skills are still essential to writing a complete set of tests. Brian Marick and his colleagues in "agile testing" have written a lot about how testers work with agile projects. One of the great values of agile software development is that most everyone on your team can develop some level of expertise at writing tests, and can use whatever knowledge they learn about testing.

    Someone in industry asked whether TDD increases the quality of code but at the cost of longer development times. I answered that many believe TDD doesn't increase net development time, because this approach includes some testing time and because the increase in code quality means many fewer bugs to fix downstream. I could not point to any controlled experiments that confirm this, such as the ones Laurie Williams has condcuted on pair programming. If you know of any such studies, I would love to hear from you. I think this is an area ripe with possibilities.

    All in all, folks were skeptical, which is no surprise from an audience with a serious bent toward traditional software engineering practice. TDD and other agile practices are as disorienting to many folks as finding myself in the Sao Paulo airport was to me. Perhaps I helped them to see at least that TDD isn't irresponsible, that it can be a foundation for sound software development.

    This day turned into one like last Sunday -- after a half day of conference, Rossana Andrade took me and Paulo Masiero on a short sightseeing and souvenir-shopping trip around Fortaleza. Then she and her husband Richard took me to a cool Brazilian pizza place for dinner, and finally they took me to the airport a few hours before my 11:10 PM flight to Rio de Janeiro, the first leg of my journey home. The day became Saturday with no fanfare, just a long flight with a layover in Recife to exchange passengers and arrival in an empty and quite English-free Rio de Janeiro airport.

    I must say thanks to my hosts in Brazil, Paulo and Rossana. They took wonderful care of me, fed me lots of authentic food, told me all about their cities and country, chauffered me around, and translated everything from pizza menus to billboards for me. Indeed, all the folks at the conference were wonderful hosts and colleagues. I can heartily recommend SugarLoafPLoP to anyone interested in participating in a patterns conference.


    Posted by Eugene Wallingford | Permalink | Categories: General, Software Development

    August 17, 2004 1:41 PM

    August 11 -- My Talk on Writing Patterns

    I finally gave my talk on writing patterns and pattern languages this morning. It went well enough, I suppose, but I broke many of the suggestions I made in the paper: too few examples, too abstract. Sigh. How can I manage so often often to know what to do yet not do it? This talk will be better the next time I give it.

    The best question at this session was about trying to write patterns that "live forever". I used Alexander's "Light on Two Sides of Every Room" as an example, and this prompted someone to point out that even the best patterns seem to become stale after a certain period of time. People wouldn't want to have two windows on two sides of their rooms if they lived in a dirty part of Sao Paulo, so Alexander's pattern is already dated; and, if Alexander's patterns suffer this fate, how can we mortals hope to write software patterns that live forever?

    My answer was two-fold:

    • The reason why "Light on Two Sides of Every Room" doesn't work in certain parts of big cities is that it is out of contex there -- the patterns that must be present before "Light" applies aren't there. If we wish to apply Alexander's pattern language in a form of diagnosis, a la The Oregon Experiment, we would have to start with patterns far upstream of this one. Indeed, Alexander would probably urge us to start from scratch somewhere else and make a more livable space to begin with!
    • In a discipline as young as building software, we can't expect that we will always understand things as well as we may in the future. So we should write patterns that document what works according to our current understanding of the world and, if we come to understand more or better five years hence, then update the language. Our pattern languages are always works in progress, as the software community discovers its communal knowledge of what gives software the Quality.

    That's my understanding today. If I learn something to make me change my mind tomorrow, I'll post an update. :-)


    Posted by Eugene Wallingford | Permalink | Categories: General, Software Development

    August 17, 2004 1:25 PM

    August 9 -- My First talk in Brazil

    Well, I made it to Brazil. Yesterday was a day that came and went with no end. I ran 18 miles in Bradenton before the sun rose, visited with parents until after lunch, and then went to the airport for an overnight flight that brought me to Recife at lunch time Monday.

    The change from English to Portugese on theb plane from Miami to Sao Paulo made the newness of my surroundings obvious. In Sao Paulo, I went through the dreaded American immigration line. The Brazilian government strives to treat each nation's citizens as that nation treats Brazilian citizens and, with the procedures in place here since 9/11, that means long lines, fewer handling stations, photographs, and fingerprints for Americans entering Brazil. I spent over two and half hours of a three-hour layover in Sao Paulo going through the immigration line. And by I use the word "line" with some hesitation. The South Americans and Europeans in the crowd certainly didn't feel limited by any idea of the linear.

    My first stop was the Federal University of Pernambuco (UFPE), in Recife. My SugarLoafPLoP co-program chair, Paulo Borba, teaches there, and he asked me to give a talk to his department. I debuted the test-driven development talk that I planned to give at the conference. It went well, despite my not having slept more than an hour since 34 hours earlier and our running so late after lunch that on arrival I walked straight into the classroom and gave my talk. The audience was mostly graduate students, many of whom write software in industry. I'd forgotten what it felt like to be in a room with a bunch of grad students trying fit whatever talk they here into the context of their own research. I spent considerable time discussing the relation of TDD and refactoring to aspect-oriented programming, JML, and code coverage tools such as Clover. This dry run led me to make a couple of improvements to the talk before delivering it on Friday to the conference audience.

    I was energized by the foment! But then I was ready to crash.


    Posted by Eugene Wallingford | Permalink | Categories: General, Software Development

    August 05, 2004 11:04 AM

    TDD and Encapsulated Objects

    Does test-driven development help us to build software with a higher degree of encapsulation? I feel like it does when I write code. But this is the sort of claim that, when made in front of students, can be exposed as either wrong or more complex than it first appears. That's because it depends on assumptions and skills that not all programmers hold.

    How might test-driven development help us to build better-encapsulated software? When we write tests first, we have an opportunity to think about our code in terms solely of its interface because we haven't written the implementation yet! In an object-oriented program, the test involves sending a message to an object in order to see whether the object behaves as expected. The object's class may may be partially implemented, but not the behavior we are testing. And we are supposed to be thinking about just the requirement at hand, not anything else.

    But how can we go wrong? If we become sloppy, we can fall into the trap of writing a test that causes a change in the object's state and then verifies that the expected change has occurred. This often requires adding a public accessor to the object's interface that is otherwise unnecessary. Even you don't intend for client programmers to use the method, it's now there. One of the lessons of interface design is that, if it's there, clients will use it.

    It's more than just sloppiness that can lead us astray, though. Testing some behaviors is not straightforward because they involve outside resources (say, a web connection) or non-trivial collaborations (say, a network error). Often it's easier to write a state-based test than a behavior-based test. But those kinds of tests usually leave me feeling unfulfilled. That feeling is my test telling me to do better.

    The idea of mock objects developed in the XP community as a way to support behavior-driven testing in the face of such difficulties. But even mock objects aren't a guarantee that we will write well-encapsulated code. Martin Fowler wrote a recent article discussing the common confusion of mocks with stubs.

    I do think that TDD encourages and supports well-encapsulated code -- but only if the programmer understands the Tell, Don't Ask principle for designing objects. And practices it faithfully. And uses mock objects (or their equivalent in your programming style) for the tough cases. That's a lot of assumptions built into a simple claim. But most knowledge works that way.

    How can you support yourself in those assumptions? Pair programming! Those XP practices really do add up to something more than their parts.


    Posted by Eugene Wallingford | Permalink | Categories: Software Development

    August 03, 2004 10:40 AM

    Reaching a Project Milestone

    Last week, I had a celebratory dinner with a group of folks who've been involved in developing a program that is now ready for prime time. It was a nice to recall the trajectory of a project that has been useful to me in several ways.

    The dinner was called by the leader of the project, Ed, a mathematics professor who specializes in early elementary education. Several years ago, he and I hooked up over his desire to have a computer program for assessing the performance of students who have been taught to basic arithmetic facts in a particular way. His research has identified a set of strategies for doing simple addition, subtraction, multiplication, and division, and a set of strategies for teaching students. What he needed was a way to tell whether and how well students were using the basic facts strategies. He needed the answer to these questions in order to demonstrate that his approach was working. More practically for teachers, answers to these questions could serve as diagnostic information, helping them know which students need more work with which strategies. Such data can make the dream of individualized instruction more of a reality.

    I did some initial design work with the math professor and then turned the bulk of the code writing over to Masa Noborikawa, an M.S. student in search of a master's project. Masa's interest lay in the role of design patterns as targets for refactoring during the evolution of a large project, and this project gave him something large enough to grow over many months, refactoring and introducing many of the design patterns he'd learned about "in the small" in his courses. The result for the larger project was a first version of an assessment tool, written in Java.

    Our first version had a couple of weaknesses that we needed to address. The first involved portability. Now, Java is characterized as "write once, run anywhere". But when anywhere includes old Macs running various versions of older Mac OS, Java -- especially its graphics library -- doesn't run as cleanly everywhere as we had hoped. The second involved networkability. As written the program was a single-user, single-machine tool. But teachers needed to be able to amalgamate data across machines and classrooms, and school districts wanted to be able to the same across different schools. The program needed to be networked with a central server and database.

    We went through an uncomfortable hiatus in the project. One of the risks for long-term projects at a school with only a small master's program is the the unreliable flow of manpower and skills. When I was a graduate student, we seemed to have an endless supply of new students looking for projects and ready to work. As a researcher at UNI, I often hit dry spots when suitable students are sparse. It's one of the downsides of a program like ours.

    Eventually I found the perfect person for the job, Ryan Dixon, an undergraduate with a lot of experience programming on Macs. Not only did Ryan have the right experience for the job, he is a good software designer, user interface designer, and programmer. He took control of the software and produced a Version 2 that addressed the above weaknesses and more. In particular, he created a parallel UI that depended on Java 1.1.8 or less, so that the program would run the same on all platforms, even the abandoned Mac OS.

    Since then, Ryan has gone off to graduate school, returning to do some work for us this summer. We also have a local consultant who has added some of the networking capability and other extensions.

    Anyway, as the project reaches the point of being marketed as a part of a mathematics curriculum for use in schools, the lead math professor brought us all together, with our families, to celebrate the achievements of the last few years. We all enjoyed a nice meal and the good company. Of course, there is always more to be done...

    This is my first experience as an academic working with internal client who is taking a project "commercial". You get to learn more from working on real projects than you can ever learn just by reading and hearing about others' experiences. I have along track record working on real projects with real clients, but this is the first on which the resulting program will be used by a mass audience outside of the client's office. In this case, our client isn't even the user -- just someone who has lots of ideas about the project and who works with the real users.

    Much of my job on this project is listening to the client figure out what he wants, listening to him talk out loud and asking questions, sometimes rhetorical. When Ed says, "Do you have two minutes?", I know two things:

    • that I'm in for a conversation longer than two minutes :-), and
    • that I have a chance to learn something more about where our project can go -- and that he may be about to learn something, too.
    As with most clients, he often doesn't really know what he wants. As with most non-software people, he often doesn't even know what is possible in a program. As a result, he asks for too much or for not enough, sometimes at the same time. By participating in the conversation, I help him find the boundaries of the technology while he thinks through the boundaries of his project. Magically, sometimes it all comes together.

    Version 3 of the program could be awesome, but how we'll get there is yet unknown.

    It's hard to get rich writing programs for educational markets, but there is a chance that this could take off. This curriculum shows promise, and the assessment program opens doors to possibilities that are unavailable to most elementary curricula. But even if we never make more than a token royalty check, the project will have been worth the time and energy.


    Posted by Eugene Wallingford | Permalink | Categories: Software Development

    August 02, 2004 8:27 AM

    TDD and Refactoring

    As I prepare my upcoming tutorial on test-driven development for SugarLoafPLoP 2004, I find myself frequently coming back to the idea of refactoring and its synergy with TDD. Fortunately, there will also be a tutorial on refactoring at SugarLoafPLoP, by Joe Yoder. I think that our tutorials will be able to work together, too, to help folks see that, to get full benefit of either, one really ought to practice both!

    That isn't to say that one can't do test-driven development alone. My coding practice in interactive languages like Scheme and Smalltalk have always been test-driven, because it's so easy to build a test suite and the desired code in parallel. On the other hand, in a language like Java, it's so easy to get caught up in the details of a big class and lose sight of the tests. This is where I find that having cultivated TDD as a practice has has made me a better programmer.

    Jason Marshall recently wrote a nice piece on the value of refactoring. He says,

    ... on my most productive day of coding ever, I had written negative 500 lines of code. On my longest sustained 'productive' cycle, on the first project I mentioned, I averaged negative 200 lines of code for four weeks ...

    This reminded me of one of Brian Foote's wonderful aphorisms: "The only thing better than a 1000-line of code weekend is a minus 1000-line of code weekend." Of course, it's sometimes hard to convince anyone still living in a LOC world to appreciate the value in your accomplishment!

    Anyone who has had to live with an out-of-control code base understands. Jason's article explains well the value of refactoring even in the absence of any other agile practices: Repetition, especially the mindless sort, ultimately makes the code too big and too hard to understand. That makes it hard for anyone to add to the program.


    Posted by Eugene Wallingford | Permalink | Categories: Software Development

    July 29, 2004 8:15 AM

    Upcoming TDD Tutorial

    Today I am working on an invited tutorial that I will be giving at the Fourth Latin American Conference on the Pattern Languages of Programs, affectionately known as SugarLoafPLoP 2004. The conference is August 10 through 13 in Porto das Dunas, a resort town in the north of Brazil.

    I am also serving as program co-chair for the conference. Being a program chair for a PLoP conference can be quite time consuming, but this has not been too bad. My Brazilian co-chair, Paulo Borba, has done a lot of work, especially with submissions written in Portugese, and the conference chair, Rossana Andrade, has shouldered most of the responsibility for the conference schedule. This has left me to focus on the writers workshop program for authors working in English and with handling basic inquiries from authors and presenters.

    My tutorial is on test-driven development (TDD). I plan first to give some background on extreme programming (XP) and TDD's place in it, and then to introduce the practices, supporting tools, and "theory" of TDD through a pair programming demonstration. Lecturing on how to do something always seems like a bad idea when you can do it and talk about it at the same time. One of the things I've been thinking a lot about is how practicing TDD can both help and hinder the evolution of good design, and how other practices such as refactoring work with TDD to even better effect. I hope for my talk to convey the "rhythm" of TDD and how it changes one's mindset about writing programs.

    On my way to SugarLoafPLoP, I am giving a talk to the Centro de Informática at the Universidade Federal de Pernambuco in Recifé. I think that this talk will also be on TDD, with a focus on interaction-based testing with mock objects. I've been learning about this idea from a recent article by Martin Fowler. I could always still talk on elementary patterns, which is the work closest to my heart, but it seems more convenient to mine the same thread of material that's occupying my mind most deeply right now.

    This is my first trip outside of North America, so I'm looking forward several new experiences! Now, back to those talks...


    Posted by Eugene Wallingford | Permalink | Categories: General, Software Development

    July 28, 2004 2:10 PM

    Edsger Dijkstra, Test-Driven Developer

    I don't usually think of Edsger Dijkstra as an "agile methods" kind of guy, but yesterday as I re-read "The Humble Programmer", his 1972 Turing Award lecture, an interesting connection formed in my mind. (I ran across this paper again at Malcolm Davis's blog.)

    As a part of Dijkstra's argument that it is possible for computer scientists to develop large programs at reasonable cost, he considers the problem of correctness. The value of testing as traditionally practiced is limited:

    ... program testing can be a very effective way to show the presence of bugs, but it is hopelessly inadequate for showing their absence.

    So, rather than write code then test it, or even write code then prove it correct,

    ... the programmer should let correctness proof and program grow hand in hand. ... If one first asks oneself what the structure of a convincing proof would be and, having found this, the constructs a program satisfying this proof's requirements then these correctness concerns turn out to be a very effective heuristic guidance.

    This sounds a lot like test-driven development to me. The tests in TDD are really more about specification than testing, and as such act as assertions, or delimiters of correctness. Each test is a claim about what the code should do. A test guides the development of a part of the code, and the body of tests and the program grow hand in hand.

    Dijkstra would certainly argue for a systematic and sound development of tests that define the system, but I do think he would appreciate TDD's emphasis on writing tests first.

    This lecture has so many neat ideas that resonate today, from the value of patterns to language design to the conservatism of the academic computer science community. I will save some of those ideas for other days.

    However, I can't resist quoting Dijkstra on the importance of computing. The conclusion of the paper is worthy of a Turing Award lecture and offers a deeply inspirational message. Two quotes stand out for me. First,

    [Computers] have had a great impact on our society in their capacity of tools, but in that capacity their influence will be but a ripple on the surface of our culture, compared with the much more profound influence they will have in their capacity of intellectual challenge without precedent in the cultural history of mankind.

    And then later,

    This challenge, viz. the confrontation with the programming task, is so unique that this novel experience can teach us a lot about ourselves. It should deepen our understanding of the processes of design and creation, it should give us better control over the task of organizing our thoughts. If it did not do so, to my taste we should not deserve the computer at all!

    The desire to understand creation and design better is exactly what drew me to computer science in my undergraduate days, what led me to study AI as a graduate student, and what continues to drive me today. Dijkstra's position also reminds me of Alan Kay's forty-year advocacy that we can -- must -- do so much more with computers than we currently do, that the digital computer can fundamentally alter how we create and communicate ideas. We are lucky to be guided by such visionaries.

    But, as Dijkstra might say, do we deserve them?


    Posted by Eugene Wallingford | Permalink | Categories: Software Development

    July 23, 2004 10:00 AM

    Professionalism and Agile Methods

    Don Gotterbarn, writes the "Thinking Professionally" column in the SIGCSE Bulletin. His most recent column (Volume 36, Number 2, June 2004) suggests that agile development methods are unprofessional. Here are some of his assertions:

    • They "do not take a systems or engineering view of development".
    • Customers are "the only stakeholders identified in system development models like agile methods...".
    • "... they quite specifically narrow our focus in dangerous ways."

    He includes RUP in those admonitions, but he reserves some of his harsher words for agile methods. He speaks dismissively of "designing a web page while agilely chatting with the customer". Later, he says, "Agile methods' emphasis on a 'people-centric view of software development' is about supporting the individual developer's needs to feel free to be creative and not about a concern for people affected by the system."

    These words sound rather disparaging, but I think they reflect a common misconception of agile methods by some in the software engineering community. Such folks often see the agile methods' emphasis on different elements of the development process as a rebuke of their own professional concerns. The result is often an overreaction to the agile methods. (Some of the hype that ushered in XP probably didn't help this situation, either.)

    In particular, I think Gotterbarn's article reflects two misconceptions.

    First, it assumes that agile methods do pay not adequate attention to gathering requirements. While some in the agile community have written a bit loosely of unit tests almost as a replacement for requirements, that's not what the agile methods actually call for. (Brian Marick makes the distinction quite nicely.) For example, XP's "planning game" prioritizes and selects from product requirements that were developed in consultation with the client. The key point XP makes about requirements is that the client should be responsible for business decisions, and the developers should be responsible for technical decisions.

    Second, the article assumes that developers using agile methods are not allowed to use their professional judgment. I don't think that any proponent of the agile methods thinks that or wants practitioners to behave this way. A professional can explore the context of a project with the client. A professional can use his or her domain knowledge when choosing stories to implement and when implementing them. A professional can acknowledge a lack of knowledge about a task. For example, several of Gotterbarn's examples are based in poor user interface design. Designing a user interface without knowledge of the intended user audience is unprofessional regardless of the development method used. Likewise for designing a user interface without knowledge of usability design.

    Perhaps both of these misconceptions ultimately come back to the agile methods' emphasis on the separation of responsibilities between the client and the developer. Certainly, agile methods depend in large part on the client specifying an appropriate system, in collaboration with the developer. That won't be different under any other software development method. Gathering requirements is still essential to building good software, and it is still difficult to do well. One of the things I like about the agile methods is their emphasis on communication, on close interaction with the client, precisely because they give the developer an opportunity to be a more active part of the conversation that defines the project.

    Agile methods don't tell us to turn our professional judgment off, or to ignore what we know about the domains in which we work. They do encourage us not to substitute our expertise for the client's in relation to the client's domain and needs. They do encourage us not to run too far head of the client's needs, not to build a system that is bigger, more complex, more costly, and more error-prone than the client needs. I don't think that any software professional or educator can disagree with these goals.


    Posted by Eugene Wallingford | Permalink | Categories: Software Development

    July 20, 2004 2:04 PM

    A Scientist Dressed in Artist's Clothing?

    Over the last couple of months, I've been following the discussion on the Extravagaria wiki. Extravagaria is a workshop organized by Richard Gabriel and Janet Holmes at OOPSLA 2004. It aims to explore how software people can use techniques of the arts "to explore research questions and explain results".

    I am a "Suzuki dad" to my daughter as she learns to play the piano. For the last few weeks, I've been picking up "Zen and the Art of Motorcycle Maintenance" during her lesson and reading a section while she works with her teacher. Yesterday, something I read brought Extravagaria to mind.

    I was reading Chapter 25, in which Pirsig talks about the synthesis of classical and romantic thought. He argues that adding the romantic as a veneer over the classical almost always results in "stylish" but unsatisfying -- even ugly -- results, both the product itself and the experience of users and designers. Instead, the classical and romantic must be united at a more fundamental level, in his notion of Quality. Pirsig then says:

    At present we're snowed under with an irrational expansion of blind data-gathering in the sciences because there's no rational format for any understanding of scientific creativity. At present we are also snowed under with lots of stylishness in the arts -- thin art -- because there's very little assimilation or extension into underlying form. We have artists with no scientific knowledge and scientists with no artistic knowledge and both with no spiritual sense of gravity at all, and the result is not just bad, it is ghastly. The time for real reunification of art and technology is long overdue.

    How much artistic knowledge do scientists require in order to avoid producing ghastly results? Can we just put a "stylish" veneer on our work, or must we study art -- do art -- so that the process is a part of us?

    I sometimes feel as though I am affecting an artistic stance when the substance of my work is little different.

    That isn't to say that I have not benefited from adopting practices from the arts. I learned a lot from Natalie Goldberg's Writing Down the Bones. Since reading it, I have always tried to write a little every day (code and text) as a way to keep my ideas, and my ability to write them down, flowing. One of the reasons that I started this blog was, in part, as an external encouragement to write something of value every day, and not just the surface of an interesting but inchoate thought. Gabriel has been something of an inspiration in this regard, with his "one poem a day" habit.

    I have also certainly benefited from learning to play the piano (well, beginning to learn) as an adult. The acts of learning an obviously artistic skill, talking about it with my teacher, and reading about it have all changed my brain in subtle but useful ways. The change affects how I teach computer science and how I read its literature; I suspect that it has begun to change how I do computer science, too.

    How easily can scientists adopt practices from the arts without 'grokking' them in the artistic sense? I suppose that this is one of the points of Extravagaria.

    If you are interested in this topic, be sure to check out the Extravagaria wiki.


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

    July 15, 2004 12:07 PM

    Continuous Feedback on the Track

    While out on a run recently, I realized that I was practicing the agile software development principle of getting continuous feedback -- without even trying.

    Most mornings, I want to control the pace I am running. Maybe I am doing a tempo run, on which I want to average my 10K pace for a few miles. Maybe I'm doing a speed work-out and need to run several repetitions of a particular shorter distance at a faster pace. I have to be careful when trying to run fast, because it's easy for me to overdo it. Then I run out of gas and can't finish comfortably, or at all. And it's even easier to run too slowly and not get the full benefit of the workout.

    Or maybe I *want* to run slower than usual, as a way to recover from faster work-outs or as a way bump my mileage up. On days like this, I have to be careful not to run too fast, because my body needs the break.

    So I need a way to pace myself. I'm not very good at doing that naturally, so I like to use landmarks to monitor my pace.

    One place I can do that is on a recreation trail near my home. This trail contains a 6.2-mile loop and has four 1-mile segments labeled. When I try to run a steady pace on this route, I used to find that my miles varied by anywhere between 10 and 20 seconds. These days I do better, but sometimes I can't seem to get into a groove that keeps me steady enough.

    I do my weekly speed workouts on the indoor track at my university's wellness center. This track requires me to do 9 laps per mile, and it has signs marking 200m, 400m, 800m, and 1200m splits. Running on this track I get feedback every 1/9th of a mile, and I can synchronize myself at the longer splits, too. Not too surprisingly, I pace myself much better on the track than on the trail. And more frequent feedback is the reason. When I get off by a second or two for a lap, I make can make a small adjustment to get back on pace -- and I can tell if the adjustment was successful within a 1/9th of a mile.

    Doing my Yasso 800s on the small track has been invaluable in helping me get faster. Even better, they have helped me learn to pace myself naturally. Now when I run mile repeats on the trail, I find that my pace rarely varies more than 10 seconds per mile, and sometimes I can clip off several miles in a row all within 3-7 seconds of each other. Getting continuous feedback as I've learned has helped me to develop better "instincts".

    I recently took my speed workouts outside to the university's 1/4-mile track, to enjoy the summer weather more and to lengthen my repeats. Running consistent 1200m repeats on the longer track is tougher, because I don't yet have the instincts for racing fast at a desired pace and because the track gives me feedback less frequently. But I hope that a few weeks of practice will remedy that...

    My goal is eventually to be able to find a groove where my pace is steady, comfortable, and right on the mark for a particular marathon time. Continuous feedback plays an important role in training by body and mind to do that.

    I think that this story may be a good way to illustrate and motivate the idea of continuous feedback in my Agile Software Development course this fall.


    Posted by Eugene Wallingford | Permalink | Categories: Running, Software Development

    July 14, 2004 6:11 PM

    Trade-offs in Software Development

    Some of my colleagues become uncomfortable when I teach our students agile software development methods. "That's just trendy hogwash," they want to say. (They mostly don't, because they are too polite.) Of course, folks from the Smalltalk and Lisp communities say just the opposite -- many of the ideas and practices of the agile software movement have their roots in ideas and practices found in those communities back in the 1980s and even earlier.

    I was reminded of just how fundamental some of these ideas are when I read one of the early chapters in Gerald Weinberg's The Secrets of Consulting, which I first blogged on yesterday. Weinberg talks about the necessity of recognizing trade-offs and making them explicit in the projects one does. Whenever the client asks for some optimal something -- the minimum cost solution, the shortest possible time, the best possible way -- the wise consultant asks, "What are you willing to sacrifice?"

    This sounds an awful lot like what Extreme Programming says about The Four Variables: cost, time, scope, and quality. To maximize or minimize one of these fundamental variables, you have to give up something for at least one of the others, maybe all. Trade-offs of this sort aren't a new idea at all, even in the world of software development punditry. Weinberg wrote his book in 1985.

    I especially like one of the examples Weinberg uses to make his case, the Trade-off Chart. Here is such a chart, updated to 2004:

    This chart shows the trade-off between speed and distance in the product category "world's fastest runner". If you want a runner to maintain a faster speed, then you will have to give up distance. If you want a runner to maintain a speed for a particular distance, then you will have to accept a slower speed. This is true of the world's fastest runners -- the upper bounds on expected performance for most -- and so it is generally true for other runners, too.

    As an erstwhile runner, I understand just what Weinberg is saying. And I am nowhere near the upper bound at any distance! Yet, like many people, I sometime forget about the fundamental trade-offs I face when working on a software project. I sometimes forget when I'm running, too, and pay the price later, in the form of fatigue or injury.

    Weinberg goes on to show how a developer or consultant can use such a chart to begin asking the right questions about the requirements for a project, and how these questions can help both consultant and client follow a reasonable path toward a working system.

    I wonder what a four-dimensional trade-off chart for XP's four variables looks like for typical kinds of software? Even two-dimensional chart showing pairwise trade-offs among the variables would be useful in understanding the forces at play when building software. These are the sort of pictures that Kent Beck draws with words in his book Extreme Programming Explained.

    So, no, dear colleagues, I'm not teaching only the latest fads in my Agile Software Development course. We are learning the basics.


    Posted by Eugene Wallingford | Permalink | Categories: Software Development