1. UAPC Second-Year Curriculum Review Committee
Final report, last revised 18 December 2008 (v2)
Committee Members:
Jo Atlee, Tim Brecht, Gord Cormack, Mike Godfrey (chair),
Omar Nafees (resigned Jan-08), Troy Vasiga
Overview
This report focuses on the recommendations of the UAPC ad hoc committee to review the
second-year core CS curriculum, as struck by UAPC in September 2007. In this report,
we outline several “cross cutting concerns” that pertain to content, pedagogy, and
delivery of these courses. We discuss the implications of the new first-year curriculum as
it affects second year. We then discuss each of the courses in the second-year core in
turn. Finally, we address several questions directed to us by UAPC.
1. Background
In September 2006, two subcommittees of UAPC were struck to review the core curriculum of
both first- and second-year CS. The two committees ended up meeting together as one during 2006-07,
and concentrated on revising the first-year curriculum, with some discussion of the implications for
second year. The main result of this committee was the revised first-year curriculum as implemented in
the new courses CS135 and CS136, which were approved by School Council on 10 April 2007. This
revised curriculum included the introduction of Scheme as the main teaching language for first year (and
functional programming and the main paradigm), and the introduction of a subset of C/C++ — termed
“C*”, informally — in the 1B term to bridge students from “programs as solutions to mathematical
problems” to “programs as instructions to run on a computer”.
In September 2007, UAPC re-commissioned an ad hoc committee to examine second-year
curriculum, since this task was only partly addressed by the previous year’s committees. The major task
of this committee was to review the second-year core CS curriculum and make any appropriate
recommendations. The committee was to review the implications of the new first-year curriculum,
discuss perceived shortcomings of the existing second-year courses, and revisit desiderata for second
year in general. The committee was also asked to consider the following questions:
Q1. Are students best served by continuing with both Scheme and C* in second year, and should one
or more additional languages be used as well?
Q2. Is mastery of specific programming languages one of the pre-conditions?
2. Q3. Is it possible for first-year courses (or first- and second-year courses) to erase all the diversity in
background and abilities of incoming students, or do upper-year courses need to adjust to
accommodate the wide mix of students?
Q4. Which programming concepts should be mastered, and in which course?
Q5. How can students obtain a broad knowledge foundation in ethics and professionalism as they
relate to computer science, and more generally to what extent should second-year courses help
students to view the discipline as one that addresses real-world problems (as opposed to one that
merely builds better tools)?
The structure of the rest of the report is as follows: Section 2 discusses terms of reference and the
framing assumptions that the committee made. Section 3 discusses aspects of second-year curriculum
that “cross-cut” many of the courses. Section 4 discusses the five core CS second-year courses
individually, and presents recommendations for each. Finally, Section 5 presents the committee’s
answers to the five questions posed above.
2. Framing and terms of reference
The committee decided to scope its deliberations by assuming that, in principal, the five courses in the
second year of our CS core were appropriate choices. One might well ask, “How much hardware /
formal logic, etc do we really need?” but we decided not to ask this question. Instead, we examined the
courses that we already have and asked the question, “How can we improve course CS2xx so that it
better meets the needs of our program?”
We also decided to concentrate on issues related to programming skills, as this was a perceived area of
concern at the beginning (“Why are students so lost when they encounter the assignments in CS350?”).
So, for example, CS251 and CS245 were not examined as closely as the three courses that require
students to write code.
During the discussions, one concern that arose was that of implementation of the recommendations
(putting the bell around the cat’s neck). Thus, the committee makes the following recommendation:
R1. UAPC should form an oversight subcommittee to ensure that the recommendations that are
accepted by UAPC are appropriately implemented. This subcommittee should also consider how to
ensure that future course offerings are “keeping with the program” and not drifting unacceptably.
3. Cross-cutting concerns of the second-year core courses
The term “cross-cutting concern” (henceforth, CCC) is borrowed from Aspect-Oriented Programming; it
refers to a semantic characteristic of a program (e.g., tax law as it pertains to an online bookstore) that
recurs repeatedly throughout the source code, but cannot easily be disentangled to become a module on
its own. In our discussions of the second-year curriculum, we noticed that many themes seemed to
3. “crosscut” the various courses. Rather than discuss each second-year course in turn and repeat the
concerns, we decided to structure the first part of this document primarily around the CCCs themselves.
The committee identified three main areas of CCCs:
C1. Concreteness and rigour of lecture material
C2. Assignments, tests, and other methods of student evaluation
C3. Course infrastructure and archives
We now discuss each of the CCCs in turn. After that, we discuss each of the second-year core courses
(CS240, CS241, CS245, CS246, and CS245) individually in Section 4.
C1. Concreteness and abstraction of lecture material
An uncalibrated list of “topics covered” is of marginal use in describing the pre- and post-conditions of
any course; some concrete measure of understanding and skill — mastery — is necessary to determine
whether or not the conditions are met. We have observed a vast disconnect between topics covered and
concepts learned, not only in programming and programming languages, but also in mathematics and
problem solving.
A perusal of public information pertaining to second year and prerequisite courses yields little insight
into the particular concepts and skills that a student must master to achieve a passing, average or
superior grade. Calendar descriptions are far too broad; course outlines provide more information but
are calibrated only by “lecture hours”; actual assignments and exams — which are increasingly hidden
from public view by password-protected on-line systems — afford perhaps the best insight. But the
degree to which students actually solve the assignment or exam problems, and the marks awarded for
those efforts, remain uncalibrated. Accreditation panels demand examples of student work and marks
for the purpose of calibration; curriculum design efforts generally rely on anecdotes.
The few calibration points we have are disturbing. For several terms, we have observed that a
substantial fraction of CS241 students have struggled to solve this problem:
Write a Java [or Scheme] program that reads a list of integers from standard input, and prints
the list twice, one integer per line. Your program should first print the list in the same order as
given in the input; it should then print the numbers again in the same order. You may use, but
are not required to use, any part of the code we have provided for Problem 1 above [which
solves the same problem, but prints the input only once]. Your solution must be reasonably
efficient [not quadratic]. Test your solution.
It is difficult to argue that these students have acquired programming skill, the concept of a data
structure, or mastery of a programming language. Assignment results in CS240 illustrate similarly low
levels of proficiency in logic, calculus and statistics. Yet these topics are purportedly covered in
prerequisite courses.
4. Second-year courses must be based on a realistic measure of the achievements and potential of incoming
students. In turn, they must have realistic and well-defined objectives. Augmenting a grandiose list of
topics covered but not learned serves no purpose.
Why the disparity between topics covered and topics learned? The feedback loop for instructors is long
and indirect. Instructors set assignments but may not set marking schemes and may not have a sense of
what graduate TAs (who themselves may be weak in the subject or just doing the work as quickly as
possible in order to earn their stipend) are actually assessing. They may not see the marks or examine
them closely until they work with the spreadsheet after the final exam. They may never see individual
student submissions, or speak to students who struggle but prefer to go to tutor consulting hours.
Instructors have little opportunity to assess the impact of their efforts on students' future studies.
CS at Waterloo is not solely responsible for the disparity between topics covered and topics learned.
Politicians, bureaucrats and parents tend to equate volume with worth and to push students to go through
the motions of a vast number of tasks, at the expense of fluency and formal understanding. Students are
encouraged to remain at Piaget's “concrete operational” level of intellectual development, at which
problems similar to previous ones are solved by pattern matching and rote. The “formal operational”
level, at which reason and logic is used to generalize beyond immediate experience, receives little
nurture.
Computer science, more than any other discipline, is predicated on the use of reason and logic to
generalize — in the most formal possible way — what we know. There is no way to “turn the crank” to
generate programs that work, to design algorithms for new problems, or to analyze those programs and
algorithms. To be computer scientists, students must advance to the formal operational stage, even if
only in tackling fairly straightforward problems. Effecting this transition is far more important than
augmenting the list of skills [sic] that a student lists on a resume. If a student can't solve the problem
above, does an employer care what language the student can't solve it in?
Waterloo is uniquely positioned to reassert leadership and innovation in computer science education.
We must be prepared to eschew the conventional wisdom to that “in an ever changing world we must
cram more and more stuff in so that our students will be competitive.” It is better to expose students to
fewer concepts and treat them more formally rather than to give them a shallow treatment of many
things; to engage them via problems on which they can act; to let them know exactly where they stand
though timely and reliable feedback; to give them a clear meaning for the things they are doing rather
than expecting them to generalize from a few examples, and to expose them to diverse ways of thinking
about computation and expressing it rather than impoverish them with a single approach.
C2. Assignments, tests, and methods of student evaluation
A general concern about second-year assignments is that they are not adequately testing students’
understanding of the lecture material or their ability to make practical use of it. There is a perception
that many students seem to be able to “squeak through” on the bell curve without having had to
demonstrate clear understanding of the material and skills they are expected to have learned, and this
shows up clearly when they get to third year (e.g., in CS350).
5. Second year is the real start of our student’s education in CS. First year is taken up mostly with basics
of programming and introducing CS concepts that students will meet again later in more depth; it is
second year where students start to develop a mature understanding of core CS concepts. We are doing
a disservice to our students if we allow them to pass through unprepared to meet the challenges of third
and fourth year. We must ensure that they are ready for their upper year courses by using evaluation
mechanisms that incrementally, rigorously, reliably, and transparently track how students are
progressing through the course material.
In brief, we feel that most assignments should be graduated in their structure, that there should be clear
criteria for success, and that reliable, objective, and on-demand feedback mechanisms should be set up
so that students will not pass unless they have demonstrated a clear grasp of the concepts and skills
expected. Finally, we note that most of the recommendations below for second year are also applicable
to first-year courses.
The committee makes the following recommendations:
R2. Assignments should be graduated in structure, allowing a clear path for weaker students
to achieve partial credit for satisfying a subset of the main requirements. Additionally, this
model also allows for stronger students to attempt more, allowing them to become more engaged
in the assignments and the course itself; bonus feature sets and open-ended extensions should
also be used to engage the top students.
For example, students might be asked to implement a set of features through the use of a
particular data structure: full marks are given for a solution that implements all of the requested
features and satisfies specified time and space constraints, but part marks are given for a naïve
solution that implements only some of the features and/or satisfies only some of the constraints.
The instructor would, of course, have to design an assignment where a range of possible
solutions would be worth different levels of credit; this is contrasted with an all-or-nothing
approach where students who do not manage to solve the problem often end up passing with
sympathy marks for solutions that do not work. This latter model is what we are seeking to
avoid.
R3. Criteria for success — in stages — should be stated clearly and rigorously.
This gives students something to aim for, and also allows the weaker students to better
understand what they may choose to attempt for only partial credit; however, in this case the
partial credit is based on what the students have implemented correctly, and students will not
receive sympathy marks for a mound of code that doesn’t compile. For programming
assignments, these criteria may be evaluated by the students themselves on-demand through the
use of Marmoset or similar tools that give automated testing feedback (assuming that the course
staff have designed appropriate tests, of course); this allows students to measure their progress as
they advance though a staged set of requirements. This is contrasted with a more typical
approach where students work on their code in isolation, and then submit their work at the
deadline hoping that they haven’t misunderstand something fundamental.
6. R4. Evaluations should be reliable and timely.
By reliable, we mean the standards of evaluation should be objective enough that any TA would
come up with a similar grade for a given assignment. This is often not the case presently;
instead, we believe that TAs are commonly encouraged to give a “reasonable” overall average,
without strong regard to the quality of the answers. By evaluation, we also include automated
feedback as provided by self-testing tools such as Marmoset. By timely, we mean that students
should have access to tools such as Marmoset that they can access on demand (well before the
deadline) to get an idea of how successful their partial efforts have been.
R5. Smaller, more frequent assignments are preferred over larger, less frequent assignments,
especially earlier on.
One of the ways in which we lose weaker students is to give them large assignments that they
have a hard time even beginning. Often, these same students will get a passing grade on the bell
curve for a solution that doesn’t really work, and so we are implicitly endorsing the view that it
is acceptable for them to muddle through their CS degree without being able to demonstrate the
core knowledge and skills that we claim to expect of them. For this reason, we advocate for the
use of smaller, more frequent assignments composed of pieces that do not have high dependence
on previous work. In this way, students are able to gain experience with the core concepts being
taught without feeling like they are falling behind. We note that this recommendation is aimed
more at earlier courses (1A, 1B, 2A), as we recognize that by the end of second year, students
also need to acquire skills in solving larger, more project-like problems to prepare them for the
assignments they will face in third year. So, for example, a small multi-stage course project may
well be appropriate for CS246 (in 2B).
R6. Debugged, reusable assignments are preferred over brand new ones.
We all know that fresh assignments, like fresh code, contain bugs; this is particularly true for
assignments that require rigorous definitions and authoritative test suites. Having a stable of re-
usable assignments that can be varied slightly from term to term would improve the reliability of
course delivery. This is not to say that no new assignments should ever be developed, but rather
that new assignment structures should be developed with the goal of becoming re-usable and
tweak-able medium- to long-term course assets.
We note that not all courses have assignment structures that are appropriate to all of the remarks above.
In particular, we note that there is no implied criticism of the use of pen-and-paper assignments; indeed,
these kinds of assignments are clearly necessary too. However, the committee feels that pen-and-paper
assignments may also benefit from several of the recommendations above.
We also note that the Marmoset tool (originally developed at the University of Maryland) was
introduced for use in CS241 by Gord Cormack, and has since been adapted for use in CS240 by Gord
and in CS246 by Mike Godfrey. So we note that all three of the second-year courses that require
programming have Marmoset in place, in principle. The use of Marmoset requires some technical
expertise to set up and keep running; the course tutor should be capable of this. However, CS240 does
not currently get a course tutor, and we feel that this issue needs to be addressed explicitly.
7. Some may be concerned about possible high failure rates if we adopt a stricter policy toward success
criteria and evaluations. If TAs are directed not to give part marks for poor answers, will many of the
weaker students now suddenly fail? Our response is that it is beholden to instructors to create
assignments with criteria that most students — but only the ones who show a clear understanding of the
concepts and skills — can meet. By providing more finely grained assignments, students are more
likely to be able to successfully complete at least some of the expected checkpoints and receive credit
for them. This is contrasted with the situation of a large assignment that many students cannot make
significant progress on, yet these same students may end up passing the course through the bell curve.
We feel that this latter approach is deeply injurious to both the students and to the CS undergraduate
program.
C3. Course outlines, infrastructure, and archives
The committee, most of whom teach second-year courses regularly, noted that it is often hard for
outsiders to easily understand what the intended curriculum of a second-year course is. There is often
poor visibility of lecture material, course outlines, and materials used in previous offerings, as well as
significant variation from stated course outlines. This is problematic not only for (new) lecturers of a
given course, but also for those who teach courses that are both upstream and downstream. How much
testing is taught in second year and how is it enforced in the assignments? In what depth is complexity
discussed in first year? Which tree structures are taught in CS240 and at what level of understanding?
By making the records of what has actually been taught (and tested) clearer and more visible, we can
improve the quality of the course offerings and ease the learning curve for new lecturers.
While all courses in CS might well benefit from these recommendations, our mandate has been to
concentrate on the second-year core. However, the committee feels strongly that — at a minimum —
all courses in all years of the CS core should adopt these recommendations.
We recommend that for each course in the CS core there be an ISG person who is responsible for
keeping the institutional memory of the course alive. We recommend that at least the following
information be kept for each term:
• A lecture topic schedule, together with copies of slides used (if any).
• A copy of the mid-term, exam, and all assignments (with instructor solutions, a small set of
student solutions, test suites, and marking schemes).
• An archive of the web pages for the term, including announcements, etc.
• A post-mortem report on any deviations from the norm or other unusual phenomena worth
mentioning about the particular offering of the course. For example, for a course that has a
reusable project the instructor may wish to indicate what variations were tried, and if any
problems were found that future instructors should know about.
These course archives would be generally accessible to all teaching staff (faculty, sessionals, ISG,
perhaps course tutors, etc.), not just those who happen to teach that particular course. These archives
would not be accessible to normal undergraduate students.
8. We would like to have the ISG person be responsible for ensuring that this material is collected each
term. Obviously, the instructors must be willing to comply too. We note that CS246, for example,
comes close to fulfilling some of these requirements already, but that not all courses do so.
We note that, in principle, UW-ACE has been designed to address some of these issues. However, the
committee members who had experience with UW-ACE were strongly negative in their appraisal of the
system. There were a number of perceived shortcomings:
• The default permissions (which is what most people use) preclude easy sharing between
instructors.
• The material expires after only 12 months.
• There is no mechanism to ensure that all of the desired material is actually stored in it (often, the
material was spread out between UW-ACE and the course web pages, and were not integrated
into a coherent whole).
• The interface is clunky and difficult to use.
The committee also had strong concerns about the responsibility for maintaining technical infrastructure
that support for second-year courses (e.g., Marmoset and other auto-testing, “submit”, online grade
management). The committee worried that there is no clear chain of responsibility: currently, both ISG
and CSCF appear to have some of this responsibility but they also each hold differing views on, for
example, who is supposed to maintain Marmoset. The committee recommends that there be a single
“go-to” technical person who would be responsible for ensuring that all of these kinds of infrastructure
needs are met appropriately; such a person would require a job mandate that allowed him/her the power
to ensure that the work can be done. The current split of responsibilities between ISG and CSCF has led
to a situation in which one group claims it is the other’s job to perform some tasks, but there is no way
of ensuring that the needed tasks actually get done. At the very least, a clear delineation of expectations
and responsibilities needs to be created, and appropriate mechanisms devised so that support requests
can no longer “fall between the cracks”.
In summary, the committee has two recommendations:
R7. There should be an ISG person dedicated to preserving course artifacts for each course
in the CS core.
R8. There should be a dedicated technical infrastructure person whose mandate is to ensure
that technical needs of second-year core courses are met.
9. 4. Comments on existing second-year core CS courses
The committee discussed and reviewed all five core CS courses by inviting “concerned faculty” (often,
the course co-ordinator) to present the history, goals, and perceived strengths and weaknesses of the
current implementations and to participate in a discussion with the committee. Gord Cormack and Alex
Lopez-Ortiz provided input for CS240; Gord Cormack and Troy Vasiga did so for CS241; Prabhakar
Ragde, Nancy Day, and Jo Atlee did so for CS245; Jo Atlee and Mike Godfrey did so for CS246; and
Prabhakar Ragde and Tim Brecht did so for CS251. The committee wishes to thanks the faculty who
participated in these discussions.
We note that although we discussed each of the five courses in detail, we feel that a more detailed
examination of each course is warranted:
R9. UAPC should revisit each of the five core courses in more detail, with a view to creating
explicit pre- and post-conditions that detail expectations of what students should be able to
demonstrate knowledge of.
After much deliberation, the committee concluded that two courses needed particular attention: CS240
and CS246. CS246 is already undergoing a major revision in light of changes to the first year
curriculum; Jo Atlee is overseeing this process and is taking into consideration the comments of this
committee. CS240 appears to be more problematic, and the committee is concerned that there is no
clear consensus among the various lecturers of which topics should be covered and in what detail.
R10. UAPC should ask that the goals, content, and delivery of CS240 and CS246 be explicitly
reconsidered in light of this report.
We now present our summaries of each of the second-year core courses in CS.
10. CS 241 — Foundations of Sequential Programs [typically taken in 2A]
CS241, a course unique to UW, has been offered since 1988. In Fall 2006 it was revised extensively in
anticipation of the changes to the first-year curriculum, and therefore serves as a pilot for many of the
changes suggested in this report. However, CS241 currently lacks an explicit course outline that
overviews the lecture topics, hours spent per topic, expectations of incoming students, and desired
outcomes. The committee felt that the current version of CS241 embodies many of the ideas suggested
in this report, and that it would make a good model for others to follow, assuming that an appropriate
course outline can be developed in a timely manner:
R11. Once a detailed course outline has been developed, the current offering of CS241 should
be used as a model for identifying well defined topics and skill levels and as a model for how to
structure assignments with well-defined graduated problems that reinforce the level of
accomplishment required to achieve marginal, median, and excellent grades.
CS241 was originally conceived as a course to detail the layers of abstraction from von Neumann
machine architecture through high-level languages such as C++, Scheme, and Prolog. The overarching
theme was that digital computing consisted of organizing binary bits into structures to realize
abstractions that could be manipulated.
Over the years its focus tended more to the use of compiler tools and the course became known
colloquially as “baby compilers”. Assignments tended to large projects using these tools. The Fall
2006 revisions returned to the original theme, reinforced by weekly graduated assignments with on-line
evaluation through the Marmoset system. Each assignment has 6 or more explicitly specified and
evaluated parts ranging in difficulty from those intended to be trivial for most students to those intended
to demonstrate mastery of the material. A few bonus questions are intended to make the best students
reach a bit; however, the intent is that all students who understand the material should be able to do all
the non-bonus parts.
The use of graduated assignments with immediate feedback has exposed — and accommodated — a
wide diversity in student abilities. Many have struggled with the simplest tasks, some eventually
succeeding and some not. Others — perhaps fewer than expected — have done all the tasks with little
effort. In addition to providing feedback to students, the system provides feedback to instructors and
course designers as to their effectiveness in imparting concepts and skills to students. “Try and keep
trying until you get it right” applies equally well to students and course designers.
All CS241 submissions consist of a single text file containing a machine language program, an assembly
language program, a Java program, a Scheme program, a DFA, a context-free grammar, a C++ program,
etc. Furthermore, the submitted programs read at most a single file from standard input and write to
standard output and standard error. All of these formats are precisely specified to represent diverse
abstractions, thus reinforcing the overarching theme of the course. Furthermore, this design is language
agnostic; there is no particular reason why a program that manipulates only standard inputs and outputs
needs to be written in a particular language. On the other hand, for pedagogic reasons, certain languages
are supported; at this time, students have the choice of Java or Scheme for all general programs
(although, for obvious reasons, not for assignments whose purpose is to teach specific notations such as
assembly language, DFAs, C++, etc.).
11. Currently, CS241 supports the use of both Java and (as of recently) Scheme. However, the elimination
of Java from the first year curriculum means that support for Java in CS241 will also be phased out.
One of the current course co-ordinators (Cormack) strongly prefers that Scheme should become the
language of choice for classroom use (e.g., examples in the notes) as well as for implementation of
assignments by students, although C* would also need to be supported at least for the SE offering.
However, others on the committee feel strongly that we should encourage C* as a programming lingua
franca for second year and de-emphasize the use of Scheme in second year.
The specific content of CS241 is well reflected by its 11 assignments:
1. (Binary) machine language programming.
2. Assembly language programming.
3. Implementation of an assembler (part I).
4. Implementation of an assembler (part II).
5. Linkers/loaders; DFAs.
6. Scanners; embedding DFAs in source code; WL — a small subset of C/Java.
7. CFGs and syntax-directed translation.
8. Parsing and parse trees.
9. WL compiler (part I).
10. WL compiler (part II). Bonus: WL optimizer, with anonymized scoreboard and prize for winner.
11. C/C++: pointers, structs, ADTs.
As incoming students are more familiar with C, it may be possible to strengthen the subset of C
presented in assignments 6 and beyond including, in particular, the translation of pointers and
procedures to the underlying machine language.
A substantial fraction of current incoming students appear to have difficulty in writing a program in any
programming language. If, as we hope, this situation improves in upcoming years, then
• the difference will be measurable, and
• the assignments may easily be recalibrated to take into account this increased ability.
In general, the level of material in CS241 is determined by students’ capacity to master it.
We note that the preparation of well-specified, debugged, graduated automatically graded assignments
requires effort that must be amortized over several offerings. The reputation of the system depends on
effective deterrence of cheating, so that students truly believe the way to “get ahead” in the course is by
doing the assignments. In part this is accomplished by showing that the assignments are do-able and
contribute to success on the exams. In part, this is accomplished by detecting and prosecuting the
cheating cases that do occur. All submissions are archived, and students, we believe, see that the
cumulative risk of cheating in CS241 is high. In early Fall 2007, nearly a dozen cases were prosecuted
with severe consequences to the students. For the rest of the term, and in other terms, we have seen only
isolated instances. Diligence must be maintained to preserve the reputation of the grading system.
12. CS 251 — Computer Organization and Design [typically taken in 2A]
The stated course objective of CS251 is: “to introduce students to theoretical and practical concepts
relevant to the structure and design of modern digital computers. The course covers computer
architecture from gate-level logic through processor design to multiprocessor and network issues.”
The committee had several concerns about the organization and delivery of this course:
1) The course is disconnected from the rest of the curriculum, and the students have difficulty
making connections on their own. Apart from CS450 (Computer Architecture) it is unclear how
much other courses in the CS program benefit from students taking CS251. Furthermore, the
committee felt that the course has not been put under much pressure to provide relevance to the
CS program.
2) Offerings by different instructors will often leave out some of the material most relevant to other
courses. For example, it appears that one recent offering left out Pipelined CPU, Memory
Hierarchies, I/O, and Multiprocessing. According to the course outline this accounts for 10 of
the 36 hours of material that should be covered.
This is probably done mainly by instructors who were teaching the course before this material
was added to the course. This is a serious concern because courses like CS 350 depend on
students knowing something about Pipelined CPUs, Memory Hierarchies, and I/O. Additionally,
because basically all modern processors are multi-core and/or multi-threaded not covering how
modern computer systems are built and execute is going to be more problematic in the future.
3) The course is often taught by non-CS faculty, including engineering faculty, ISG, and sessionals.
The committee has the following recommendations:
R12. Create closer ties to the material in CS 241 and CS 350.
For example students write and execute MIPS assembly language programs on a simulator.
Currently, students do paper exercises in one of the assignments related to instruction
scheduling that could be made more interesting and relevant by writing code that executes on a
simulator (e.g., System/161 which is used in CS 350).
R13. Find CS faculty who are able to cover all of the material in the course outline and are
willing to teach it regularly.
R14. Re-examine the relevance of the course material with respect to the rest of the CS
program. The course should emphasize what one needs to understand about computers and
computer architecture to develop effective and efficient software. For example, the text
“Computer Systems: A Programmers Perspective” by Bryant and O'Hallaron might provide a
good outline for such a design.
13. CS245 — Logic and Computation [may be taken in 2A or 2B]
The biggest question mark with respect to CS245 is the degree to which it varies with the course
instructor. In particular, there is variance in the number and types of proof methods covered: natural
deduction only; vs. semantic tableau only; vs. natural decision, semantic tableau, and transformation
proof. The course also varies in how much of the underlying formalization of the mathematics is
covered. For example, one version of the course walks though the proofs of soundness and
completeness of a proof system (in detail for Peano axioms, sketched for axiomatic set theory). Another
version exposes students to the concepts of soundness and completeness, and discusses their
implications with respect to what is provable; this allows it to devote more time to the use of logic to
model and reason about programs (e.g., Z specification language, more time on program verification).
CS245 is often held with SE112, with shared assignments and exams. In the case of SE112, the
Software Engineering Curriculum Committee has expressed a strong preference for the more applied
version of the course that focuses more on the use of logic to model and analyze programs, and less on
the underlying mathematical proof systems. But in the case of the SE program, the ultimate emphasis of
the program's curriculum is on design, and the more applied version of this course more closely aligns
with that curriculum philosophy.
In the case of the CS program, there are no strong external factors to guide decisions about this course's
curriculum. Individual faculty may favour one version of the course over another, but it is difficult to
argue that any one version is most appropriate for all CS students. While courses such as CS445 and
CS446 do benefit from its treatment of logic, there are no upper-year courses that depend directly on the
specific technology covered by CS245. Rather, the main purpose of the course is to improve students'
ability to reason formally about the software that they write, and the specific logic and proof systems
covered in the course are simply the concrete mechanisms that students use to practice and improve their
skills. To use an analogy, the Math Faculty probably has few strong views about what programming
language is taught in the math core, as long as the choice of programming language does not get in the
way of the students' learning.
R15. Given that no upper-year course depends directly on the specifics of the CS245 course
material, and given that keeping the course content flexible will make it easier to find
instructors and will make it easier logistically for CS245 and SE112 to share resources, the
committee recommends continuing to allow the current variances in the delivery of CS245.
14. CS240 — Data Structures and Data Management [typically taken in 2B]
CS240 is an intermediate course in data structures and analysis of algorithms. CS134/CS136 provide
an elementary introduction to searching and sorting and the analysis of algorithms; however CS240 is
the first course in which these topics are covered rigorously. CS240 should provide a solid foundation
for the theory of computing, for the implementation and analysis of practical data structures, and the
selection of appropriate data structures for solving large-scale problems in data management. At the
current time, students' background is inadequate in nearly all of these dimensions. Many students are
unable to implement or analyze even elementary data structures and algorithms, and are also unable to
apply the mathematics and statistics from math prerequisite courses. The content of CS240 is an
eclectic and superficial mix of traditional data structures and algorithms topics.
R16. CS240 should be restructured to identify much more concrete and specific skills to be
taught, with both written and programming assignments that clearly reinforce these skills, and
for which the level of accomplishment can clearly be measured. This level of accomplishment
should be calibrated to students' abilities and continuously monitored.
The prerequisite mathematics and programming skills should not be assumed; where they are lacking
they should be included in the course content until such time as the prerequisite courses can be
strengthened. There is some reason to believe that the revisions to CS136 will yield students better able
to manipulate elementary data structures; more effort should be made to ensure that necessary
mathematical skills are acquired in MATH courses, particularly proof, calculus and probability theory.
The W08 section is offered as an example of how the course and assignments may be restructured to
meet these goals. Programming assignments were done in C* with simplified interfaces to isolate the
particular skills; some theory questions were recast so as to facilitate automatic evaluation; some were
submitted as PDF written documents. We recommend that the workflow of marking the written
assignments be restructured so as to provide timely on-line feedback.
The CS240 designers noted that incoming students had very poor programming and math skills, the net
effect being that programming was de-emphasized and that marks and student opinions of the course
were bimodal. The committee questions whether the majority of students are mastering any substantial
subset of the material covered, and whether the division of topics between CS240 and CS341 is
appropriate.
In Winter 2008 one of us (Cormack) taught CS240 based on a model similar to that of CS241. Weekly
graduated assignments reinforced topics from lectures. A very small subset of C++ (exactly that taught
in CS241) was used in programming assignments. Instead of using standard input and output, all
assignments used ADTs specified by .h files. Standard libraries were disallowed in general, and the first
several assignments explicitly used a RAM ADT to reinforce the underlying model of computation.
Later assignments used C++ structs, pointers and strings.
In addition to programming assignments, written assignments (as PDF files either created electronically
or scanned from paper) were submitted to Marmoset. Previous terms had used PDF submission, and
incorporating it into Marmoset worked well. However, marking and communication of results used the
15. traditional batch approach, which was not nearly as effective as the automatic grading of programming
assignments. In general, submission rates and grades were worse for the written assignments than for the
programming assignments. One assignment — on asymptotic analysis — was done so poorly that all
students were allowed to re-submit without penalty. In spite of this, and extra tutorials, the average
mark for this part was still below 50%.
With minimal effort, Marmoset could be modified so as to queue written submissions to be marked in
quasi-real-time by markers. Such a setup promises to provide more immediate and useful feedback to
students who struggle. Obviously, one cannot allow students an unlimited number of submissions to
“get it right” but one could allow a few with the net effect still being less load on TAs.
As for CS241, Marmoset provided the instructor with feedback as to the progress of the class and their
level of mastery of the assignments. Many students had fundamental problems that can only be
attributed to inadequate background or ability. Many students simply could not do simple calculus,
create logical proofs, or write simple C programs (e.g., binary search). Many students simply don't
understand pointers in C and are flummoxed by linked data structures and strings. It is hard to argue
that these difficulties are simply the result of inability to code. They illustrate a fundamental lack of
understanding of the foundations of data structures.
The C/C++ runtime environment is unforgiving to those who are confused. The RAM ADT used in the
first six assignments reported uninitialized and invalid RAM access; no such safety measures were
available for subsequent assignments, and they are sorely needed. It is well and good to say that students
should be able to deal with an unsafe run-time environment, but a substantial number can't.
Labs should be reworked so that all submissions run in a safe environment, and so that the restricted
subset be enforced so as to prevent students from wandering into unsafe territory, and also to reinforce
the underlying model of computation.
It may be appropriate to use the MEF Linux servers and the valgrind utility to effect this
environment. Cormack has been tasked with investigating appropriate tools to use for C/C++ labs in 1st
and second year.
Finally, CS240 is the only second-year course that does not have a tutor or tutorials. This oversight
must be remedied. As noted above, a substantial number of students struggle with the mathematical and
programming foundations that they need to succeed in the course. Furthermore, mentoring students in
frequent assignments requires a much more hands-on approach than can be effected by a couple of five-
hour-per-week IAs and TAs whose only role is marking written assignments. CS240 urgently needs a
full-time tutor.
R17. CS 240 should be allocated a tutor.
16. CS246 — Software Abstraction and Specification [typically taken in 2B]
There seems to be some discontentment among the faculty and the students with the content of CS246.
Among the committee members, the degree of discontentment varies, with SE members showing greater
appreciation of the course material than non-SE members. But all committee members feel that the
course could be improved.
For one thing, there is an overarching concern that the second-year curriculum does not adequately
prepare students for the level of programming proficiency and maturity expected in third- and fourth-
year courses. The current CS pedagogy is for programming assignments to be small (i.e., weekly
assignments) in first-year and in 2A courses, so that the assignments are achievable by the vast majority
of students and so that students master the skills of programming-in-the-small before attempting to
tackle larger programming projects. However, this strategy creates a large gap between the size of
programs that students write in 2A and the size of programs that we expect them to write in CS350 in
3A. CS246 seems to be a natural choice for progressing students' programming capabilities to larger
programs, especially given that one of the objectives of CS246 is to cover software engineering
principles, practices, and technologies that help to improve programmer productivity.
Second, the changes to the first-year curriculum will have a strong impact on the content and delivery of
CS246 — more so than on any other second-year course. The current CS246 curriculum focuses on
object-oriented modelling and design, with an emphasis on creating modular designs that can be
partitioned into separate workpieces (to support team development) and that can be changed easily. The
design part of the course starts by addressing the implementation of ADTs/objects in C++, then
progresses to advice on how to structure code involving collections of objects so that the resulting
design is adaptable, and concludes with design advice on how to package classes into subsystems. It
assumes that students coming into the course have experience with object-oriented programming from
their 1.5 years experience using Java. In the new curriculum, however, students will enter CS246 with
minimal OO experience. So, if nothing else, CS246 will have to change to accommodate the change in
students' backgrounds.
As for other factors to consider, there are a few upper-year courses that depend directly on the specific
concepts covered in CS246:
• The fourth-year SE courses assume knowledge of UML, OO design, and design patterns.
• The HCI course, CS349, benefits from the coverage of design patterns.
• CS443 assumes knowledge of C++.
• CS350, CS452 and other courses that require design documentation could take advantage of
students’ knowledge of UML as a design notation. Also, co-op and post-graduation programming
jobs in industry are direct consumers of the OO principles and patterns covered in the course.
Within UW, the main objective of CS246 is to improve students' programming capabilities so that
they can solve larger and more complex software problems. In this sense, any upper-year course
that involves large software projects is an indirect consumer of this course.
The committee makes the following recommendation:
17. R18. The main goal of CS246 should be to teach students how to write good, medium-sized
programs efficiently. With respect to curriculum, such a course should focus on modularity,
abstraction, testing, and using software tools.
With respect to pedagogy, assignments should be a combination of written exercises and medium-sized
programming assignments (i.e., assignments that take 2-4 weeks to complete) that build on one another.
The projects should emphasize modular, incremental development. Ideally, the marking schemes would
also favour incremental development, with partial credit for correct implementation of components or
for correct implementation of a subset of the desired functionality. Perhaps the instructor could suggest
weekly milestones, to help students bridge the gap from weekly programming assignments to medium-
sized assignments.
CS246 has a history of automatically testing programming assignments and manually evaluating
program designs. There is a tricky trade-off here, because the focus of the course is on design, so the
design of assignments is heavily weighted. However, such weighting can encourage students to hand in
only designs and not working code. More thought needs to be given as to how to balance these aspects
of the programming assignments.
There is some question as to whether students should be able to do the projects as teams. On the one
hand, students get more programming practice by working individually. On the other hand, they do
eventually need to progress to working in groups, and they can learn from their peers in such
arrangements. A compromise (which has been tried previously in CS246 and appears to be successful)
may be to make the latter assignments group based. This approach may have the added benefit of
helping the weaker students to recover if they are struggling with a term-long project.
We note that the use of Marmoset (and similar tools) is a double-edged sword. While students can use
Marmoset to gain confidence that they are working towards a complete working solution of an
assignment, it also implicitly moves the onus of “how can I ensure that my program is correct?” away
from the student. The committee strongly recommended the use of Marmoset for early programming
courses, but some members thought that it would be advisable to wean students away from using it as
CS246 progresses, so as to better prepare them for the expectations of third year.
Finally, we recommend that the programming language in CS246 be C++. Either C++ or Java would be
acceptable, from the point of view of using an OO programming language. But it would be too difficult
to introduce students to both languages in the same course because of the subtle differences in their
execution semantics. C++ is preferable to Java because (1) it allows for exercises and programming
assignments that require students to work with pointers, (2) students will come in with some experience
in C* from CS136 and CS241, and (3) students will need proficiency with C and pointers in CS 350.
PROPOSED CURRICULUM
Introduction (0.5 wk)
•
Introduction to object-based programming (2.5 wk): objects, messages, method invocation,
•
classes, interfaces, object modelling in UML, ADTs, decomposition problems
Incremental development (1.5 wk): module dependencies, incremental build, Makefiles, version
•
control, libraries and namespaces
18. Testing and Debugging (2 wk): black-box testing, white-box testing, coverage, test harnesses,
•
debugging strategies, assertions
Exceptions (1 wk)
•
Generics (1.5 wk) : STLs, template parameters, basic templates
•
Object-oriented programming and design (2.5 wk): inheritance, polymorphic types, OO design
•
principles (least knowledge, substitutability, delegation), OO design patterns (template method,
strategy, composite, iterator)
Professionalism (0.5 wk)
•
Addendum: CS246 and SE students
SE students will enter CS246 having already seen and worked with some of the above topics, such as
modules, ADTs, objects, and Makefiles. Plus, their primary programming language in first year and 2A
will be a subset of C++, so they will enter the course with some working knowledge of C/C++. As
such, allowances will need to be made for the overlap between CS246 curriculum and the SE students'
background. The extent of the overlap is approximately two weeks of material — the first two weeks of
the above proposed curriculum.
We recommend modifying the SE sections of CS246 to start the course with a 2-week module on some
topic that is not covered in the CS sections of the course. Possible topics include more advanced C++
concepts like class design (equality, assignment, copy constructor, print), parameter overloading, and
friends; or a scripting language.
19. 5. Answers to UAPC questions
The committee discussed the questions posed by UAPC mentioned at the beginning of this report.
Q1. Are students best served by continuing with both Scheme and C* in second year, and should one
or more additional languages be used as well?
The committee agreed that C* should be a major teaching language of second year and that no
new language (e.g., Java, Python) should to be introduced in second year. This is not because
we saw no value in other languages, but rather because we felt that it was more effective to
spend the students’ intellectual resources on basic procedural and OO programming using a
familiar language, rather than memorizing the strange details and “magical incantations” that
learning any new language requires.
The committee failed to reach consensus on the use of Scheme beyond first year. The two
points of view are summarized as follows:
Practice makes perfect: Students need as much practice in programming C* the
lingua franca of industrial and systems programming as they can possibly get, and
using Scheme beyond first year diminishes this quantity. Students would be best served
by having at least two full terms of using C* before attempting to take operating systems
in their 3A term. Therefore the use of Scheme in beyond first year should be proscribed
in favour of C*.
Foundations before practice: Second-year courses should assume competence in both
Scheme and C* and may oblige students to use either as appropriate for learning the
course material. Scheme may be a more appropriate choice, for example, for describing
parse trees, recursive algorithms, and so on. A mastery of these concepts is more
important than their particular realization, and the use of two languages serves to
reinforce the difference between abstraction and realization. The use of Scheme where
appropriate is likely, in the end, to yield better and more versatile programmers in
general, and better C* programmers in particular. Scheme vs. C* is not a zero-sum
game.
At the moment, Scheme and Java are used as implementation languages in CS240. C* is being
added as an option to replace Java; however there are no plans to eliminate Scheme. C* and in
particular the relationship of C* to the underlying RAM machine, are the subject of study in their
own right (even in the current offering that uses Scheme and Java as implementation languages).
CS240 should use C* as the primary implementation language (replacing Java and C++) ; CS
246 should use C++.
Q2. Is mastery of specific programming languages one of the pre-conditions?
With respect to programming language and facility in programming in general, the committee
felt that an appropriate pre-condition for second year would be:
a. Proficiency in functional programming using Scheme.
20. b. Some facility with procedural programming in C*.
The committee felt that proficiency in C* should be a post-condition of second year. Concretely,
proficiency at C* would mean that students:
a. understand how pointers, memory, objects, and references work;
b. understand both the procedural and object-oriented programming paradigms;
c. are be ready for upper year courses such as CS350 that require the ability to write
programs in C* that are hundreds of lines long; and
d. have experience in a programming language that is used in industry (both for co-op
placement and eventual graduation).
In particular, the committee noted that expectations for object-oriented programming skills will
be scaled back from previous years, as students will not encounter the topic until CS246 (in the
2B term), and the emphasis on object-oriented programming within CS246 will be greatly
reduced from that of previous years.
However, we also note that the purpose of a CS education is to produce computer scientists, not
“language lawyers”; there is certainly no expectation for the students to become experts in all of
the dark corners of C++, for example.
Q3. Is it possible for first-year courses (or first- and second-year courses) to erase all the diversity in
background and abilities of incoming students, or do upper-year courses need to adjust to
accommodate the wide mix of students?
Realistically, the committee does not feel that second-year core courses will be able to erase the
diversity in ability, experience, and maturity in our students. The committee felt that first- and
second-year courses should be structured with clearer guidelines as to what minimal expectations
should be and should not promote students who fail to meet these standards. However, even
with clearer expectations, we will still have a spectrum of abilities to consider. The committee
felt that we should design our courses so that weak and strong students can get value out of the
lectures and assignments. This relates strongly to the previous discussions of clear expectations,
objective grading criteria, and incremental assignments.
Q4. Which programming concepts should be mastered, and in which course?
The discussions of the individual courses in Section 3 of this report address this issue.
Q5. How can students obtain a broad knowledge foundation in ethics and professionalism as they
relate to computer science, and more generally to what extent should second-year courses help
students to view the discipline as one that addresses real-world problems (as opposed to one that
merely builds better tools)?
We decided not to address this topic in detail. However, the revised version of CS246 proposed
in this document addresses this topic in lecture.