Blog Hop

June 25, 2010

I started this blog last November as an exercise in reflective practice, and it was my first experience in blogging. I have enjoyed this endeavor, but I have decided to move the blog for the time being. Until further notice, you can follow my writings at The content and themes of the blog will not significantly change — just the service provider.


Unit Testing Google Wave Robots

June 18, 2010

I am happy to report that I am now successfully running unit tests on my Wave robot. For this example, I will show how to configure a unit test for a Java robot that responds to the WAVELET_SELF_ADDED event, which is fired when the robot is first added to a wave. My sample robot is designed to do something very simple: when added to a wave, it records the root blip id in an AppEngine data store. Specifically, I’m using JDO to persist objects in the data store.

The configuration comprises:

  • Eclipse with the Google Plug-in. This is not strictly necessary, but you would be crazy to go without it.
  • All of the robot development libraries. The installation of these is covered in the Wave Robots API Java Tutorial. You will need to make sure that gson.jar, oauth.jar, wave-model.jar, and wave-robot-api.jar are on your build path. (I’m skipping the version numbers in the files for clarity.)
  • AppEngine libraries on the build path as described in the Local Unit Testing of the GAE documentation. Two of these were in my google plugin directory but not attached to the project: appengine-api-stubs.jar and appengine-testing.jar. These I put into a lib folder and added to the classpath. Other libraries may be in the war and not yet on the build path, such as appengine-api.jar and appengine-api-labs.jar.

My WaveletRecord class for this example is very simple:

public class WaveletRecord {
    @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
    private Key key;

    private String rootBlipId;

    public String rootBlipId() { return rootBlipId; }

Now, we’re ready to write the unit test. Once again, the GAE/J Local Unit Testing documentation will get us started. We need to have a LocalServiceTestHelper along with setUp and tearDown methods, just like in their example:

public class RobotTest {

    private final LocalServiceTestHelper helper =
        new LocalServiceTestHelper(new LocalDatastoreServiceTestConfig());

    public void setUp() {

    public void tearDown() {

I want to test how my robot responds to onWaveletSelfAdded, so I need a WaveletSelfAddedEvent object. As described in the Debugging Wave Robots article, we can use AppEngine logs to extract the JSON messages that are actually passed between the Wave client and a Robot. In my case, I have just such a String from my logs:

{"events":[{"type":"WAVELET_SELF_ADDED","modifiedBy":"","timestamp":1276086048055,"properties":{"blipId":"b+X"}}],"wavelet":{"creationTime":1276086030870,"lastModifiedTime":1276086048055,"version":13,"participants":["","",""],"participantRoles":{"":"FULL","":"FULL","":"FULL"},"dataDocuments":{},"tags":[],"creator":"","rootBlipId":"b+X","title":"Bugs squashed","waveId":"!w+JkmJGit7A","waveletId":"!conv+root"},"blips":{"b+X":{"annotations":[{"name":"conv/title","value":"","range":{"start":0,"end":14}},{"name":"lang","value":"en","range":{"start":0,"end":14}},{"name":"lang","value":"en","range":{"start":15,"end":431}}],"elements":{"0":{"type":"LINE","properties":{}},"14":{"type":"LINE","properties":{}},"15":{"type":"LINE","properties":{}}},"blipId":"b+X","childBlipIds":[],"contributors":[""],"creator":"","content":"Nothing to see here, please move along.","lastModifiedTime":1276086031862,"parentBlipId":null,"version":8,"waveId":"!w+JkmJGit7A","waveletId":"!conv+root"}},"robotAddress":""}

Of course, we can’t just put that into our Java code directly: we have to escape all of the quotation marks to make it a valid String literal. However, once we do that, we can make a handy constant like this:

private static final String SELF_ADDED_EVENT = "{\"events\":[{\"type\":\"WAVELET_SELF_ADDED\",\"modifiedBy\":\"\",\"timestamp\":1276086048055,\"properties\":{\"blipId\":\"b+X\"}}],\"wavelet\":{\"creationTime\":1276086030870,\"lastModifiedTime\":1276086048055,\"version\":13,\"participants\":[\"\",\"\",\"\"],\"participantRoles\":{\"\":\"FULL\",\"\":\"FULL\",\"\":\"FULL\"},\"dataDocuments\":{},\"tags\":[],\"creator\":\"\",\"rootBlipId\":\"b+X\",\"title\":\"Bugs squashed\",\"waveId\":\"!w+JkmJGit7A\",\"waveletId\":\"!conv+root\"},\"blips\":{\"b+X\":{\"annotations\":[{\"name\":\"conv/title\",\"value\":\"\",\"range\":{\"start\":0,\"end\":14}},{\"name\":\"lang\",\"value\":\"en\",\"range\":{\"start\":0,\"end\":14}},{\"name\":\"lang\",\"value\":\"en\",\"range\":{\"start\":15,\"end\":431}}],\"elements\":{\"0\":{\"type\":\"LINE\",\"properties\":{}},\"14\":{\"type\":\"LINE\",\"properties\":{}},\"15\":{\"type\":\"LINE\",\"properties\":{}}},\"blipId\":\"b+X\",\"childBlipIds\":[],\"contributors\":[\"\"],\"creator\":\"\",\"content\":\"Nothing to see here, please move along.\",\"lastModifiedTime\":1276086031862,\"parentBlipId\":null,\"version\":8,\"waveId\":\"!w+JkmJGit7A\",\"waveletId\":\"!conv+root\"}},\"robotAddress\":\"\"}";

Yes, it’s ugly, but it allows us now to easily create a real WaveletSelfAddedEvent using Google’s gson library, which you have as part of the robot development libraries. We just need to make a GSON factory, parse the JSON, and pull out our event from the bundle. That is,

GsonFactory gsonFactory = new GsonFactory();
Gson gson = gsonFactory.create();
EventMessageBundle bundle = gson.fromJson(SELF_ADDED_EVENT, EventMessageBundle.class);
WaveletSelfAddedEvent event = (WaveletSelfAddedEvent) bundle.getEvents().get(0);

Now, unlike in the GAE/J Local Unit Testing approach, I am going to use JDO to check that my robot is behaving as expected. Will this work? Honestly, it surprised me, but it sure does: configuring the LocalServiceTestHelper was enough to allow us to get an appropriate PersistenceManager using the usual techniques.

The following code will create for us a query that will return all WaveletRecord objects:

PersistenceManager pm = PMF.get().getPersistenceManager();
Query query = pm.newQuery(WaveletRecord.class);

We will also have a sanity check to ensure that there is nothing there yet.

List records = (List) query.execute();
assertEquals("We should start out with nothing in the datastore.", 0, records.size());

Running the robot is easy as pie once we know what we’re doing. My robot is implemented as DataCollectorServlet, so I can poke it and see how it reacts to being added to a wave.

DataCollectorServlet robot = new DataCollectorServlet();

How do we know if this worked? If there is now a WaveletRecord in the datastore and its root blip ID matches the one in the event. Notice that I don’t have to hardcode that root blip ID anywhere: I’ll just pull it out of the event. The event is not a “mock object”: it’s a real event as Wave would generate, but it has all the nice lightweightness of a mock object.

records = (List) pm.newQuery(WaveletRecord.class).execute();
assertEquals("There should be exactly one record returned by the query.", 1, records.size());
WaveletRecord waveletRecord = records.get(0);
assertEquals("The rootblip id of the single wavelet record should match the one in the event.",
  event.getWavelet().getRootBlipId(), waveletRecord.rootBlipId());

That’s it! The unit test passes, and now test-driven development can commence.

(Turns out my robot actually writes a blip on being added, too, but testing that is left as an exercise for the reader.)

CS1, Thinking, Programming, and Impediments to success

June 11, 2010

The following situation has arisen several times in my teaching of CS1. In an introduction to object-oriented decomposition, I demonstrate to my students how to create a MyRectangle class. This class has a constructor that takes the x, y, width, and height of a rectangle, and it has one public draw method. We’re using Java, so the draw method accepts a Graphics parameter. The draw method is very simple: g.draw(x,y,width,height), using the attributes of the rectangle. This gets us into a nice discussion of “rectangleness”, which is represented by the class, versus individual immutable rectangles, which are represented by objects. (NB: I do not follow the naive textbook approach and have every object follow whitebox design with public accessors and mutators for all attributes. That is just training students in established bad practice. I teach them to make every object immutable whenever possible.)

From here, I have them create a MyOval class. The students check out the Graphics class in the Java API and realize that there’s a drawOval method that looks deceivingly like the drawRect method, and sure enough, the implementation of MyOval is strikingly similar to MyRectangle’s.

Then, after extended discussion about encapsulation and object-oriented systems as collections of objects that communicate by passing messages, I explain the following problem: when I define a circle, I don’t like defining it by its bounding box. Unlike a rectangle or an oval, I want to define a circle by a center point and a radius. This is “natural” to me, the user of the MyCircle class. I give them this challenge, and away they go.

First, they look for a drawCircle method in the Graphics class. There is no such thing, so I point out that circles are special cases of ovals. Then, one of two things happens: either the student jumps in and writes MyCircle’s draw method to be exactly like MyOval’s, or they make some attempt to determine how a circle would be specified by its center and radius instead of a bounding box. Note that in the former case, the circle will end up in the wrong position.

I recently gave this assignment, and for the first time, none of the students got it right. Usually, it’s a minority, but at least somebody gets it. The astonishing thing this semester is that only one or two submissions showed any evidence of analysis of the problem, doing anything beyond simply calling g.drawOval(x,y,radius,radius).

The solution to the problem is, to me, so dazzlingly obvious that it’s hard to explain. It is simple geometry: if you want to get the x,y coordinates of the bounding box of a circle, you subtract the radius from the center point’s x and y. It’s geometry, easily solved visually:

the circle is specified by center x,y and radius, so the solution is quite easyAs far as I can tell, there’s only two reasons how someone could get this wrong if they were actually trying to succeed:

  1. They did not take the time to read and understand the problem before solving it. This is a common failure among CS1 students: given a problem, they start at the keyboard instead of in their brains. They start typing and typing and typing and expecting magic to happen. After all, isn’t that what the professor does in class?
    No it isn’t! For all of these drawing problems, I always start with “analytical mode”, drawing the problem out on the whiteboard, asking for suggestions, talking through my thought process, and then writing the code for it.
    This is, in my estimation, a failure of knowing how to think, i.e. a failure of reflective practice. This is the result of inculcation in regurgitative non-learning, in which points are given for showing up.
  2. They lack mathematical literacy. In this particular case, they have no grasp of geometry or the relationships between numbers. I know much less about acquisition of mathematical literacy than I do about the science of learning in general, and so the specific evidence is unclear to me. However, I have noticed that, when faced with any mathematical task — even trivial ones — many of my students will completely lock up. Of those who don’t completely freeze and wait to be handed an answer, many of these go off in crazy flights of fantasy, totally unrelated to the problem at hand.

These two factors are not independent. Although the latter may have more specific roots in the cultural establishment of math anxiety, I suggest that they may have the same root cause: students do not know how to learn. This can manifest as (1) not taking the time to read and think about a problem before answering it and (2) never needing to learn how to solve problems. This experience makes me think of Polya’s How to Solve It. I was underwhelmed reading the book because I knew most of it already, but I think this is significant: I would wager that successful students (i.e. students of life, not just people taking classes) would read that book and see it as confirmation of what they already do. On the other hand, it’s exactly the kind of thinking that many people lack, such as struggling CS1 students.

Bringing this back to the task at hand, I am forced again to look at this question: What should students learn in CS1? There are a few reasonable answers, but the two that rise to the top of the list are (1) how to think computationally and (2) how to program. The latter is dependent on the former. The former is dependent on being able to do elementary mathematics, which itself is dependent on being able to learn in the first place. If it’s true that many of my students don’t know how to learn and don’t have fundamental mathematical literacy, then it’s no wonder that CS1 courses have 50% withdraw and failure rates!

I am reminded of an uncomfortable discussion I had with a mathematics professor about programming. She was pooh-poohing the study of programming, claiming that it was easy to teach programming to her upper-level mathematics students, so therefore programming was easy. I take this as anecdotal evidence of my theories: give me a class full of students with mathematical aptitude and problem-solving skills, and I could certainly teach them the simple task of programming. They already know the hard part—thinking and problem-solving strategies—that I am challenged to teach to everyone else.

The All-Novices in the Cooperative Game

June 3, 2010

I am about halfway through Alistair Cockburn‘s Agile Software Development: The Cooperative Game, second edition. The book provides an excellent and thorough coverage of agile methodology development, which dovetails nicely with my need to develop an effective methodology for Fall’s game programming course. I have taken copious notes and written several times in the margin, “How will this apply to CS315?”

Chapter 5.1 was added in the second edition in response to the myriad misunderstandings of the agile manifesto. In this chapter is Cockburn’s first explicit consideration of dealing with an all-novice team, which is my situation in the Fall. This paragraph is from p258, in a section addressing the misconception that agile methodologies only work with expert developers.

If I had a project consisting only of novices, I would put my money on their doing better with an agile rather than a plan-driven process. I can’t imagine novices coming up with a meaningful plan from the beginning, or delivering a successful project by sticking to that plan, or updating the plan every time they found a mistake in it. An agile process would call for them to work together, integrate frequently, test their code, show their results to their sponsors and users, and update their plans and working practices accordingly. With this approach, they would have a better chance to learn and improve within the project.

I have been using agile methods to varying degrees in my project-oriented classes, and I am certain that they engender learning and improvement. I think it’s worth teachers’ time to look at the best practices espoused by the signatories of the Agile Manifesto.

This has important implications for classes, especially project-based, studio-based, or otherwise constructivist learning experiences. Perhaps the most important is that it is the students’ right and responsibility to modify the environment after each iteration.  If students are the owners of their learning experiences, then they must be held to the same level of citizenship as a programmer on a software development team. I find that there are two impediments that challenge this, namely the professors’ and the students’ comfort with conventional objectivist designs. The sooner we can break both populations’ addictions, the sooner we can get on with learning.

Further on in the same section, Cockburn tackles the problem of the ratio of novices to experts. In dealing with an excess of novices, in situations in which getting rid of them is not an option, he recommends:

Use an agile process with the smallest number of people possible to get the job done; let the rest of the people do anything they want just so long as they don’t interfere with the progress of the development team. (Emphasis in original.)

There’s a convenient solution to a production-intensive learning experience in which firing personnel is not option. Of course, these folks should not expect “A” grades.

(I plan on writing more about how Cockburn’s observations and advice can apply to the design of project-oriented courses, but this particular paragraph inspired me to start tonight.)


June 2, 2010

One of the teams (or, I think, one of the members of one of the teams) from my Android-HCI class cleaned up the class project and has released it on the Android Market. If you have an Android device, open the market and do a search for “Elemental”, and you’ll find a nifty little periodic table application by Team Phosphoric. Well done, gentlemen! I found posting an Android app on the Market to be a fulfilling personal experience and a great learning experience as well.

The good folks at Google have promised that we should get a Web-searchable version of the Market soon, as well as cloud-to-device messaging, which will allow me to give you a link directly to the app installation. Until then, you’ll have to do it the conventional way.

Search for game design advice brings me back to Tim Ryan

May 26, 2010

In the Spring, I team-taught a colloquium on history education game design with my respected colleague Ronald Morris, a professor in the History Department at Ball State. Regular readers may have noticed that I have not written much about this experience. I’ll get to it. Or not.

This colloquium explored the design of a game for Indiana 4th grade students. The production of a high-quality educational game remains Ron’s main focus in the project, while I am also specifically interested in exploring how students can learn directly from the mechanics of the game as opposed to the layer of story atop the mechanics. My interest in this question goes back several years to when I first read Raph Koster‘s Theory of Fun for Game Design, which is the first book I recommend to anyone who expresses interest in Fun. (That’s “Fun” with a big “F”, by which I mean the serious study of fun.)

The students in the colloquium created some compelling physical prototypes in the first half of the semester, and the goal was to create a high-quality design document from these experiences. Unfortunately, the final document does not meet production standards. We are still planning to build a game, and specifically, my Game Programming students will be building it in the Fall. The task of finalizing the design document therefore falls in my lap, and it’s not unwelcome.

In the colloquium, we used Wave to start the document, but performance was not adequate for our purposes, and so the document moved to Google Docs. I do like docs for quick and dirty documents, but years of wysiwym editing in LaTeX have left me with very little patience for wysiayg editors. A lot of the advice I encountered online recommended the adoption of wikis for design documents, and so my first step was to import the existing Docs file into Google Sites, a general-purpose Web site creation utility that has convenient wiki-like features. The two main advantages of Sites are that (1) I already know it well and (2) I don’t have to configure a wiki server.

I quickly found, however, that the format of the original document was not empowering my creativity. I felt like I was mechanically creating pages but with no real end in sight. I decided to invest an afternoon to find the best practices for design document creation and management, beyond the technology and into the realm of content.

Suffice it to say that you can find a lot of advice about game design on the Internet. I bounced from site to site and eventually ended up on’s General Game Design page. There, I downloaded some templates and started tinkering. The one that stood out happened to be based on Tim Ryan’s series of articles at GamaSutra, the first on proposal and concept documents and the second on functional and technical specifications. If you’ve read this far in hopes of finding my links to the best advice I’ve found, and the title of this post didn’t give it away, there you go.

The funny thing about these articles is that these are the same ones I read four years ago in my first foray into serious game development (serious development, that is, not serious games at that point). The articles themselves are from 1999, and a lot has changed since then in both the games industry and the academic treatment of games. I’ve read many books on game design and design theory since then, and Ryan’s articles still stand out as having just the right balance of practical advice and theoretical soundness. They have also helped me identify my Summer path more clearly:

  1. Write a concept document and share it with my stakeholders, who are Ron and a few key undergraduates whom I will be trusting with high-responsibility tasks in Fall. The concept document is essentially complete and I am awaiting feedback.
  2. Write a functional specification.
  3. Write a technical specification, while concurrently developing the milestone schedule.
  4. If necessary, develop any core software architecture that will be required before the Fall semester begins. After all, I will be managing a team comprised entirely of novice developers.

That leads me to my next great quandary: how do I manage a team of 30 novices on a critical project? But that’s a topic for another day.

Writing, Scholarship, and Software

May 22, 2010

My Google I/O travelling companion was Brian McNely, professor of Rhetoric and Writing in the English Department at Ball State. He told me a bit about his personal daily scholarly regiment: he reads at least 50 pages a day and writes at least 750 words, the latter supported by I respect this endeavor, knowing how, as a professional academic in a university, there are other forces that can drain the time and focus that should be devoted to academic pursuits. Brian clearly enjoys his scholarship, even when he has to make sacrifices to meet his goals.

This made me think about my own scholarship and personal goals. There is a great contrast between my feelings between Fall and Spring of the last academic year. In Fall, I felt productive and I also felt that I was learning. In much of the Spring, I was frustrated. (Interestingly, as I look back at the past semester’s writing to pull out those links, there is more positive ideas there than I remembered there being. That’s encouraging. I suppose I need to spend more time reading my own blog.) One of the major differences between the two semesters was that in the Fall, I was inventing: working on Confluence was a great experience, as I’ve said before. I know that I love the process of inventing software systems, and so I have been actively seeking out opportunities to leverage this as both personal fulfillment and scholarship. This Summer, in fact, my time should be nicely split between some interesting Wave and game projects. I embrace Boyer’s model of scholarship, and pertinent here is the scholarship of application.

When I try to tie these ideas together with Brian’s 50/750 regiment, I hit a contradiction. Clearly, as a professional scholar, I could just adopt 50/750 myself, and this would undoubtedly improve my scholarship. However, I would also like to have time for invention, for creating software. Unfortunately, you cannot measure productivity in software, so how does one set personal goals for invention?

Last semester, I set aside time Friday afternoons for writing on this blog, and I am happy with the results. I feel like I have been able to crystallize several concepts by writing them, and it has given me an outlet to explore and ripen new ideas. There were only a few times in the semester that I was unable to set time aside. However, even in reflecting on this writing, it was done in relatively small spurts of about an hour. That is, it was done in what Paul Graham calls the manager’s schedule. I know, from years of development experience and many semesters of frustration, that if I want to successfully build a system, I need to do it on the maker’s schedule. (Incidentally, adopting inbox zero has significantly improved my ability to occasionally adopt the maker’s schedule during the academic year.)

I don’t have a plan, then, for how to deal with this contradiction of wanting measurable goals for something that brilliant designers call unmeasurable. I have developed some experience using Scrum and MSF in leading teams, and I could always adopt these for myself, except that I am not sure that “maintain development momentum” or “mitigate one high-impact risk” are goals that I can meet. One one hand, these managerial techniques were designed for teams, and on the other, neither really is a measurement of productivity. Of these two, the idea of measuring momentum via Scrum or similar techniques is somewhat appealing, partially because it could hone my capacity for estimating time requirements, and in the end, time may be the only invariant I can use to commit to invention.

No conclusions, but I’m open to ideas.

On People

May 19, 2010

I’m at Google I/O 2010 right now and having a good time. The best story so far, though, is from the flight out here.

A passenger comments to the flight attendant, “It must be hard to smile and be nice to people all the time.”

The flight attendant shrugs and responds, “People are good.”

An inspiring philosophical lesson at 30,000 feet.

The Story of Sasha

May 14, 2010

This past semester, I have served as an external evaluator for a high school student’s independent study project, the creation of a graphic novel called The Story of Sasha. I got into this role almost accidentally: I met a girl at a friend’s 40th birthday party, and somehow we got to talking about comics. Turns out “Anna” is a senior and needed an evaluator, so even though it’s a bit beyond my scholarly expertise, I agreed to it.

The student created a blog at, and I encourage you to check it out. I have shared it with some professional artists and designers, and they all agree that it’s phenomenal for a high school project.

Although comics are not my area of expertise, I am a longtime fan of the medium and I’ve done a bit of light reading on the form, the most relevant of which is Understanding Comics. (See also Scott McCloud’s excellent TED talk on the topic.) During the Q&A after the presentation, I got the feeling that most of the crowd was not actually interested in deep discussion, so I suppose I’ll have to schedule a coffee meeting with Anna to dive into such topics. (It is worth noting that her writing and art instructors, who were giving her the independent study credits, did not know anything about graphic novels, which I think left me as the “expert” in the room. Not the first time, but never in this subject!)

Two things struck me about the project that I want to write about here: the project-as-capstone and the presentation itself. I’ll start with the latter, since quite briefly, it was excellent. No bullet points, no gratuitous animations. Anna clearly has a good sense of style and design, even if she was not aware of their application to effective presentation delivery. She was well-prepared, speaking confidently from her knowledge of the topic, clearly showing adequate preparation in terms of both the content and the delivery. I found myself wishing that my Computer Science majors could have been there to see a truly excellent presentation. As I’ve written about before, I fear that many of our university students actually get worse at presentations during their time in higher education due to both exposure to and indoctrination in ineffective techniques.

It became evident during Anna’s presentation that the project itself was a capstone in the fullest sense. She  cited her art, writing, and biology classes as being explicitly influential on the project. When I asked for elaboration, she mention also math, history, and other science classes as being places where she was able to both explore and expand on her work. This is a phenomenal example of the power of intrinsic motivation and cross-cutting projects. It’s not that her school is any less bureaucratic than any other, but she made the opportunity to explore The Story of Sasha wherever she could. I get the feeling that within the University, there may be less opportunity for this: students get loaded with “other peoples’ work” rather than being able to bring their unique interests and background into cross-cutting experiences. (Originally wrote “learning experiences”, which is redundant, since all experiences are learning experiences.)

I look forward to tracking Anna’s progress as she moves on to art school and from there, to a successful career.

Reflection on 345/545

May 6, 2010

It’s the end of the semester, and today were the final presentations in the HCI class. I am taking this opportunity to reflect upon this teaching experience, an attempt to articulate some of the joys and frustrations of this semester.

  • I am disappointed that none of the projects have been released on the Market. I suppose it’s a good thing for the students that I didn’t make this a requirement to get an A. I do not think that any of the teams even seriously looked into the distribution requirements, which makes me sad, because there are many interesting elements here, including application permissions, application signing, certificate management, and dealing with feedback from unknown and unexpected users.
  • I knew going into the semester that the vast majority of the students would not be able to adequately scope their projects, and so agility was built into the expectations. However, I did not fully account for the negative relationship between estimation inexperience and team size.
  • I suspect the results would have been better overall with smaller team sizes: this would have increased both accountability as well as motivation, since individuals would be needed. I tried to keep the number of teams relatively small so that I could keep track of each team and provide directed feedback. In retrospect, seven teams were too many for me keep track of anyway, and so having more teams would not have been a significant drain on my time. It would have complicated in-class presentations, but I suspect this would not have brought as much difficulty as benefit. (Many wise students suggested smaller team sizes in their reflections.)
  • The risk matrices were generally useful, but the MSF Team Model was not. From personal experience and the stories told in students’ reflections, it is clear that most students did not understand the meaning of the roles, and I suspect the “role” system caused more difficulty than was necessary. Students with no prior experience in significant team development projects have no useful mental framework for roles, and so, in retrospect, I should have predicted that they wouldn’t appreciate what the roles meant. Point in case: “testing” doesn’t mean anything to a student who has never tested anything. (The fact that students can go through the foundations courses and never discuss testing is a problem, and it’s being addressed by the introduction of 222.)
  • The teams suffered from communication breakdowns and uncertainty about tasks at a fine grain. The risks of the risk matrices were slightly too abstract for the students with no prior team or large-scale development experience to handle. I suspect one of the following would be preferable: (1) more rigorous management of the risk matrices, including more directed feedback from me about the appropriateness of risk articulation; or (2) a more quantitative, task-oriented project management technique such as the product backlogs of Scrum or the use of issue tracking software.
  • Having community partners was important, especially to the best students. Many of the students clearly learned important lessons from these interactions. Some of them were lessons I was also trying to convey, but it was much more effective to work with the ignore-the-professor-in-favor-of-outsiders phenomenon than it was to fight against it!
  • The reflections were worthwhile except that I needed to set stricter deadlines. I am not a fan of deadlines for such work, but they are needed for my own sanity, not for the students. Because I did not set explicit deadlines, I have been inundated by “reflections” the last two days. The astute reader can guess the quality of reflections that are being sent in right before the end of the semester. Hint: they’re not the ones I really enjoy reading, and I think they primarily why I have been so blue today.
  • Expanding on the previous point, it was very rewarding to read the reflections of the responsible students. By responding to their metacognitive essays, I felt like I was having a direct and positive impact on their individual learning, a great win for a constructivist. I realize that there are two potential complications in this: (1) there is a chance that better rhetoric is being rewarded over authentic-but-inarticulate reflections, and (2) a student who is savvy with emotional intelligence could manipulate me through these essays. I think either are acceptable costs. Regarding the first, writing is an extremely important skill that students should have anyway, and regarding the second, I think the best of the students are more honest than that.
  • Expanding on this point again, it was frustrating that some students still did not get the point of the reflections, or perhaps what metacognition is about. I am concerned that perhaps I did not articulate the requirements clearly enough, but with targeted individual responses, I’m not sure what else I could do aside from assigning them to do exercises out of Pragmatic Thinking & Learning.

There are some things I would change if I could do this course again, but mostly, I wish I could take all of my “A” students and with me and do some really great things. Unfortunately, the curriculum doesn’t work this way: this is a terminal class, and I have to let go. (Another reason I’m a little blue today.)

For any of the negative aspects of the course, I do believe that the students really did meet the learning objectives of the course. By and large, I think they understand better the role of humans in software development, both as users and as collaborators. For those who are not graduating (who are most), I look forward to watching them move through the curriculum and seeing if the course really had a measurable effect, especially as they take the capstone course— projects of which are often characterized by team trouble and bad user-interfaces!

Also, the design of the course met the primary constraint: the students were able to hit the ground running with a mobile application development project of their own design, while I was free to enjoy the birth and first few months with my second son. I wouldn’t want to do this every semester, but this one worked out fine.