Title: Course Wrapup
Date: 2013-12-26
Category: Course
Tags: notes
Author: David Evans
Template: graph2
Slug: course-wrapup

In Fall 2013, I was assigned to teach _cs4414: Operating Systems_, a
course that is required for our BS Computer Engineering and BS Computer
Science (and taken by about half of our BA Computer Science students as
an elective).  I had never taught operating systems before, or for that
matter, even taken an operating systems course at any level[^1], so
didn't have much idea what should be in such a course.

This was my first chance to teach a real course since [my experience
teaching and helping develop MOOCs at
Udacity](http://blog.udacity.com/2013/02/cs101-one-year-later.html).
I'd been asked many times by reporters how my experience teaching open
on-line courses would change my in-classroom teaching, and never had a
very good answer to this at the time.  I didn't have much of an idea in
starting this course, but did have a perspective that led me to question
many aspects of traditional courses that are typically taken for
granted.  

<center>
<a href="http://www.rust-class.org/static/images/graduates.jpg"><img src="http://www.rust-class.org/static/images/graduates.png" width=700></a><br>
<b>cs4414 Fall 2013 Graduates</b>
</center>

## Styles of "Operating Systems" Courses

From my survey of "Operating Systems" courses at other universities, I found two main types:

1. Courses where students build a simple operating system.  

2. Courses where students learn about low-level programming and build
robust and scalable systems, but don't build an operating system.

The first type of course has a clear and estimable goal: provide
students with a deep understanding of low-level aspects of computing
systems by building their own OS kernel.  This is typically done using
some kind of processor emulator such as
[Nachos](http://homes.cs.washington.edu/~tom/nachos/) and with some code
provided.  Exemplars of this type of course include 
MIT's [_6.828: Operating System Engineering_](http://pdos.csail.mit.edu/6.828/2012/),
Yale's [_CS422/522: Operating Systems_](http://zoo.cs.yale.edu/classes/cs422/2013/),
Princeton's [_COS381: Operating Systems_](http://www.cs.princeton.edu/courses/archive/fall04/cos318/),
and Harvard's _cs161:
Operating Systems_ course taught by [Margo Seltzer
(2013)](http://www.eecs.harvard.edu/~margo/cs161/) and [Matt Welsh
(2007)](http://www.eecs.harvard.edu/~mdw/course/cs161/) (famously featured in [_The Social Network_](http://chomaloma.blogspot.com/2011/02/social-network-inaccuracies-regarding.html)).  Since building
an operating system is a fairly huge undertaking, such courses typically involve
teams that work together for the full semester and [require](http://www.thecrimson.com/article/1994/3/10/cs-161-consumes-students-free-time/) [survival guides](http://www.eecs.harvard.edu/~margo/cs161/resources/survival.html).

A variation is to not attempt to build a full simple OS, but to instead
make modifications to an existing OS.  For example, University of
Washington's [_CSE 451: Introduction to Operating
Systems_](http://courses.cs.washington.edu/courses/cse451/13sp/overview.html)
uses a sequence of projects where students modify a Linux kernel.  Such
courses are great for providing deep understanding of operating systems,
and this type of actual OS hacking is probably needed to gain a strong
understanding of how operating systems really work at a low level.

The second type of course is often still called "Operating Systems", but
is better named "Systems Programming" or something like this.  Exemplars
of this type of course include CMU's [_15-213: Introduction to Computing
Systems_](http://www.cs.cmu.edu/~213/) (and the excellent associated
[textbook](http://csapp.cs.cmu.edu/)], MIT's [_6.033: Computer Systems
Engineering_](http://web.mit.edu/6.033/2013/wwwdocs/index.shtml) and
Penn State's [_CMPSC311: Introduction to Systems
Programming_](http://www.cse.psu.edu/~mcdaniel/cmpsc311-f13/).  The goal
of these courses is to teach students what they need to know to build
robust and scalable computing systems, as well as the most interesting
intellectual ideas from operating systems.  Such a goal is less
well-defined than the goal for the first type of course, but more
relevant to the vast majority of students than the first type of course.
Very few people will ever actually write or work on an OS kernel today,
but all programmers need to understand low-level aspects of computing
systems if they want to build efficient, scalable, and robust
computing systems.

I believe there is a great case for offering a core Operating Systems
course of the first type and encouraging interested students to take
such a course as an elective.  When an "Operating Systems" course is
required for all students (which is the case for two of the three
computing majors our department offers), though, it seems better to me
to focus on the more broadly-applicable aspects of building scalable and
robust computing systems.  Everyone benefits from learning these, and
the benefit-suffering ratio should be much better than in classes where
students focus on building an operating system.

## Choosing a Language

Perhaps the most controversial decision I made was to use the Rust
programming language as the main language for course assignments.  The
jury is still out on whether or not this was a good decision in the long
term.  I've written up more about this in [a separate
post](|filename|./usingrust.md).

## Avoiding the Trough of Mediocrity

The problem with most university classes is they are too big to provide
students with the individualized attention and flexibility that
maximizes learning, but too small to provide the economies of scale
needed to develop really high quality teaching materials and to engender
substantial student contributions.

<center>
   <div id="div_trough_chart" style="width: 750px; height: 270px;"></div>
   <div class="caption">
The amount of teacher attention per student drops as the class size
increases, but the resources that can be put into developing quality
teaching materials increases with the number of students, and most
importantly, the value of student contributions increases dramatically
(both because there are more students, and each student has more
incentive to put effort into major contributions).
Unfortunately, most University classes fall in the "trough of mediocrity", with 20-150
students.  
   </div>
</center>

Despite the problematic class size (for Fall 2013, cs4414's enrollment
was 65 students), I tried to avoid the trough of mediocrity by (1)
assuming the effort invested in developing the course would be amortized
over more than just the students in this semester's course, and (2)
finding ways to provide a flexible and individualized experience even in
a fairly large class.

### Amortizing Development Effort

I've always spent a ridiculous amount of time preparing lectures, at
least compared to what most faculty do and what is typically
recommended.[^2] I feel like it takes me at least 10 hours to prepare a
decent lecture, and often 2-3 times that to prepare a good one (the
preparation time is a bit more for topics that I don't initially know
much about, which is the case for much of this course, but I find it is
often harder to produce a good lecture about something I already know
well than about something I am figuring out myself as part of developing
the lecture).  This means that in a semester where I am preparing a new
class, developing the lectures is taking up the majority of my time.  

Although I might want to do this anyway since I enjoy it (especially
when I'm learning about new and interesting things) and take personal
pride in it, it would be very hard to justify this investment for just
this semester's class.  That's not to say it isn't worth trying to make
lectures good even for a small class, but in a "trough of mediocrity"
size class, instead of spending ~30 hours a week developing the two
lectures, I could meet with each student individually for 20-30 minutes
each week, which I hope would be more useful for most students than
sitting in 2.5 hours of lectures (even if I hope they are good ones).

The way to justify putting a lot of effort into developing lectures for
the classes, is to view it as a more generally valuable resource that
will be useful to me in future semester, and will hopefully also be
useful to many people who are not in my class.  Although our department
is notoriously fickle in scheduling classes and unwilling to plan more
than a semester ahead, I did get an agreement that I would get to teach
the course at least one more time before starting this year's course.
Reusing a prepared lecture still requires effort, both to improve and
update the content and to refresh my memory about what to talk about,
but much less effort than it takes to build a new lecture from scratch.

The better way to amorotize effort in producing course materials is to
make them open so people outside the class can also access them.[^3]
This is more likely to be useful if the material covered is different
form what many other courses have covered before, and if lectures and
notes can be released in a way that makes then useful on their own.  I
wasn't able to do this for all the classes this semester (and have plans
to make things more useful externally next semester), but nevertheless
did manage to produce materials with some external impact.  Its hard to
measure this definitively, but according to the [SlideShare
stats](http://www.slideshare.net/DavidEvansUVa/presentations?order=popular),
several of the lecture slides have been viewed by over a thousand people
including the lectures on [Rust](|filename|../classes/class2/class2.md)
([SlideShare
page](http://www.slideshare.net/DavidEvansUVa/class-2-first-ride-on-rust)),
[processes](|filename|../classes/class4/class4.md) ([SlideShare
page](http://www.slideshare.net/DavidEvansUVa/class4-used)),
[trust](|filename|../classes/class13/class13.md) ([SlideShare
page](http://www.slideshare.net/DavidEvansUVa/reflections-on-rousting-rust)),
[synchronization](|filename|../classes/class12/class12.md) ([SlideShare
page](http://www.slideshare.net/DavidEvansUVa/synchronization-26991419)),
and my personal favorite, [_Inventing the
Future_](|filename|../classes/class26/class26.md) ([SlideShare
page](http://www.slideshare.net/DavidEvansUVa/inventing-the-future-28862093)).

### Providing Individualized Experiences

The biggest challenge for larger classes is to still provide a
sufficiently individualized experience for the class to be valuable for
most students.  Even in a curriculum with set prerequisites, students
enter classes with very different backgrounds and aptitudes, and even
more different interests and goals.  

**Providing Alternatives.** Since this course is required for two of our majors, a large fraction of
students are taking the course merely because it is required to satisfy
a graduation requirement (about 20 out of 65 students gave this as the
main reason for taking the course on the initial course survey).  I
don't really think this course should be required, so wanted to give
students who felt their personal goals were not well aligned with mine
an opportunity to do something different.  I explained this in [Class
5](|filename|../classes/class5/class5.md), and even made it a [question
on the
midterm](https://docs.google.com/forms/d/113q31QJ3X-56XGXrElH_BCZts31qzKFxRbN57Cuyt0k/viewform),
but no one asked to take advantage of it.  I'm not sure if this is
because everyone thought their goals aligned well with what I was doing
in the class, or because students realized coming up with a good
alternative would be more work than doing the course as prescribed, but
at least felt that by providing the option gave me some more justifiable
freedom in designing the class.

**Open-Ended Assignments.** One way to individualize a class is to provide
more flexible assignments.  The challenge in doing this for a larger
class is maintaining consistent grading (I'll talk more about grading
below) and providing enough guidance for individual (or small team)
projects despite the medium-sized class.  We did that this semester by
leaving it mostly up to students to decide what extensions to do at the
end of the two main problem sets: [Problem Set
2](|filename|./ps/ps2/ps2.md) is about implementing a shell and included
a couple creative exercises and a final problem to implement extensions
chosen by the students; [Problem Set 3](|filename|./ps/ps3/ps3.md) is
about implemeting a multi-process web server, and left it for students
to make most of the major design decisions (given a starting framework),
and to extend or improve the performance of their server however they
could.  I think these could have benefitted from a bit more structure,
in particular in how performance is measured, so plan next semester to
release the most (if not all) of the benchmarking tests as part of the
assignment.

The [final project](|filename|./ps/project/project.md) was completely
open, and students could do whatever they wanted in teams of any size so
long as they could convince me it would be worthwhile and satisfy at
least two of the goals of the project (fun, relevant, technically
interesting, and useful).  There were only a few teams that had hard
times finding fulfilling projects.

I met with each project team twice during the course of the 5-week
project (scheduling meetings using [ohours.org](http://www.ohours.org/evans)).  This took
a lot of time, but I think was worthwhile, and most groups ended up
doing [projects that I thought were
worthwhile](|filename|./ps/project/results.md), and some did things I
thought were spectacular (including one team that built an [ARM kernel
in Rust](https://github.com/wbthomason/ironkernel) which I hope to use
for a new assignment in the next class)!

## Course Forum

I tried using Piazza for course discussion.  This was my first
  experience using Piazza, and there were some things I really liked
  about it, but other things that are quite unsatisfactory.  A major
  problem is that it is closed by nature.  There is no way to share
  discussions with people unless they register for the Piazza course
  site.  It is also not very effective at encouraging useful class
  discussions, and has no easy way to link discussions in Piazza to
  course content.

The only topics that ended up getting semi-reasonable discussion were
  questions from problem sets where students were required to post
  something in the forum.  The forum did work fairly well for students
  getting answers to technical questions, and we benefited greatly from
  participation in the course forums from some Rust experts who were not
  students in the class.  Piazza does have some easy-to-use polling
  features which I used a few times during the semester, which I think
  worked okay but not great.  To be fair, I don't know of anything that
  works better, and I don't know of anyway to have a very effective
  course discussion forum without having several thousand active
  students.  I'm not sure how much of this is a technology problem, but
  there are some important technology-support features needed for good
  discussions that no tool I know of supports well.

## (Minimizing) Grading

The usual reason given for not scaling courses is the difficult in
grading a large number of students.  From what I see, most CS courses
put far too much effort into grading, and most of that effort could be
much better invested in teaching.

There are four main reasons to grade assignments and exams in a course:

1. To provide (hopefully) useful feedback to students.

2. To assess how well the course is going and how well students (as a
group) are understanding key ideas.

3. To provide motivation to individual students, who might otherwise not
be inclined to spend time on the course.

4. To measure student performance and have data for assigning final
grades.

Of these reasons, #1 is very important and essential to actual learning
in many cases.  But, assigning detailed scores for each question doesn't
provide any useful feedback.  Providing written feedback on code or
answers can be useful.  This can require a huge amount of effort to do
well, and it is often demoralizing to discover later that most students
are not actually reading these comments.  More commonly, students do
read them but not necessarily understand them, and it is pretty rare for
a student to come to office hours to ask about comments on an old
assignment.  So, I decided it was more useful to spend the time I would
normally spend on providing written feedback in having in-person
post-assignment meetings (these were called "demos", but that's probably
a misnomer, since they were mostly about asking students to explain how
they did something and why, and following up with questions about
whether other options would be better and how they would do things
differently if there were other requirements, etc.)  The time was fairly
tight for these (15-20 minutes for each team), but I think it was enough
to be more valuable than spending far more time on written feedback.

In addition to the in-person demos, students submited a web form with
some questions about the assignment, as well as assessments to indicate
whether they were able to solve each main problem.  Having students
self-grade this seemed to work well, and since they had follow-up demos,
even without relying fully on the honor system I think there were
sufficient incentives for students to answer them honestly (and I'm not
aware of any instances where students claimed to have solved a problem
they didn't at least appear to solve).  The submitted forms provided a
useful basis for structuring the demo, and I could quickly read through
the submissions at the beginning of a team's demo and follow-up on any
interesting answers.

This way of doing grading scaled well to a 65-person class, and can
probably work for a somewhat larger class, but I'm expecting to need to
do things a bit differently [next semester](|filename|./spring2014.md)
(with around 115 students).

In addition to the problem sets, we had a midterm exam, which was mostly
short answer questions drawn from the provided course notes.  This
mainly served purpose #2 and #3, with the hopes that it would encourage
students to review and synthesize the course material that was not used
directly in the problem sets, as well as give me a sense of how well
students were understanding things.  To minimize grading time, I used the _Efficient Grading Algorithm_ described in [Class 13](|filename|../classes/class13/class13.md):

```rust
use std::rand;
fn grade_midterm(answers: [~str]) -> float {
    if (/* answered question 9, which asked students if there was a particular answer I should read */) 
        return great_answer(answers[9]) // and possibly look at other answers
    let numq = answers.length;
    let urand = rand::random::<uint>() % numq;

    if good_answer(answers[urand]) { 1.0 } 
    else if good_answer(answers[(urand + 1) % numq]) && good_answer(answers[(urand + 2) % numq]) { 1.0 } 
    else { ... // grade all answers }
}
```

This made it feasible for me to grade all 65 exams in a reasonable
amount of time, while still providing grades that were either fair or
generous to students.  I don't know of anyone else who uses such a
grading scheme, but I strongly encourage it.  I think most faculty feel
there is some kind of moral obligation to at least superficially grade
everything students do on an exam, but its hard for me to see why this
is necessary.

I don't think courses should be designed to emphasize #4 (grading for
the sole purpose of sorting students), especially courses mostly taken
by third-year and higher students.  Providing more precise grading
matters a lot in first and second year classes, since these are the
prerequisites for later course, and are courses where students benefit
from clear signals if they are in the right major for them.  By the time
students are in 4000-level classes, though, they have mostly decided on
their major, and the difference between getting an A- or B+ or between a
B- and a C+ should be very minimal.  It only really matters for helping
second-rate companies who are not able to hire the best students more
efficiently determine which students to interview, and I don't think its
really up to us to do that.  Much better to spend time on teaching, and
on providing ways for students do things that will help them get jobs at
first-rate companies or succeed in graduate school.

# Outcomes

I am, of course, not the least biased judge of how the course went, but
I was reasonably happy with how things worked out for a first run of a
brand new course.  For a more balanced view, you can [read the student's
course evaluations](|filename|./finalsurvey.md).

There were definitely places were things were not as well prepared as
they should have been, especially with [Problem Set 2](./ps/ps2/ps2.md)
(which initially included a problem that was effectively impossible) and
[Problem Set 3](./ps/ps3/ps3.md) (which I think mostly worked okay, but
was delayed because of problems getting it ready and didn't provide some
starting code it should have).  My attempts to make up for lack of
assignments with low-level kernel hacking by looking in-depth at the
Linux source code in class didn't work for most students, and I think we
should have done some more concrete things with lower-level
implementation issues.

I enjoyed the demo-based grading a lot, and from what I've heard, most
students found it worthwhile (although for some, a bit nerve-racking,
even though demos were designed to be low-pressure).  Since the course
size for the next semester will be about double the 65 students in the
first course, I won't be able to do all the demos and project meetings
myself, but will need to find a way to distribute this effort.

   <div class="mhighlight">
[Sign-up for the open Spring 2014 Course](|filename|./spring2014.md)
   </div>

<center>
<img src="http://www.rust-class.org/static/images/rust-class-orange-2.jpg" width=430>
</center>

# Thanks

I'd like to thank my spectacular assistants, [Weilin
  Xu](https://github.com/mzweilin) and [Purnam
  Jantrania](https://plus.google.com/118148872969843886927/about), who
  did much of the work in creating the assignments, and provided a great
  deal of help to students throughout the course.  I'd also like to
  sincerely thank
  all the students who were brave enough to stick with an experimental
  and unusual course, and especially the many who made great
  contributions to the class.  I'd also like to thank the contributors
  from outside the class, especially Corey Richardson and Huon Wilson,
  Rust experts to answered many student questions in our course forum
  and in the #rust IRC.


_Please feel free to comment with your identify or anonymously below, or
  to email me directly to follow-up on any of the comments here.  I'm
  especially happy to get comments from any students in the course who
  might disagree with my take on things._

<div id="disqus_thread"></div>

<script type="text/javascript">
        /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */
        var disqus_shortname = 'rust-class'; // required: replace example with your forum shortname
	var disqus_url = 'http://www.rust-class.org/pages/wrapup.html';

        /* * * DON'T EDIT BELOW THIS LINE * * */
        (function() {
            var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
            dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
            (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
        })();
</script>
<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a>


[^1]: When I was an undergraduate at MIT, students had a choice between
taking [_6.033: Computer System
Engineering_](http://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-033-computer-system-engineering-spring-2009/)
and [_6.035: Computer Language 
Engineering_](http://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-035-computer-language-engineering-spring-2010/)
(Compilers).  The 6.033 course (at the time) was mostly reading papers
and writing a long paper, whereas the 6.035 course was a large project
to build a compiler.  I was very interested in building a compiler, and
didn't like reading and writing much, so it was an easy choice to take
6.035.  

[^2]: Faculty are typically told that they should spend one hour of
preparation time for each hour of class time, and this seems fairly
consistent with what faculty surveys report (see Table VII-12 of the
[2012 Faculty
Survey](http://www.coopercenter.org/sites/default/files/publications/Final%20Complete%20Report%20to%20print.pdf),
which reports UVa faculty spending 15.6% of their teaching time in
classroom hours, 16.6% on course preparation, and 6.6% on grading, and
faculty with research emphasis spending 14.9% of their total time on
teaching, and working 57.9 hours per week.  This implies that a typical
research-emphasis faculty member is spending 1.4 hours per week on class
preparation).

[^3]: Sadly, the standard systems people are encouraged to use at our
university are closed by default, so very few of the course materials
others produce here are accessible to anyone who isn't enrolled in the
class.  I think public universities should _require_ faculty to make
their course materials open, except in cases where they can provide a
strong justification for not doing so, but at least at this public
university, it is more of a battle to be permitted to release materials
openly.
