CS 2 at our university covers a fairly standard list of topics, including two dimensional arrays, recursion, algorithm analysis, and linked lists. In the process of teaching these topics, we strive to develop/refine/improve our students' programming abilities in three aspects:
"Programming in the small" refers to a student's ability to implement a small, well-defined, but non-trivial algorithm, such as detecting whether somebody has won a game of Connect 4, or finding the largest set of people in the room who share the same birthday.
"Programming in the large" refers to a student's ability to define and implement small set of classes that work together to solve a problem and exhibit good design (avoid duplicate code, separation of concerns, etc.).
At this level, we also want our students to improve their ability to articulate how they know their code is bug free, and automatically test their code (unless automating the tests would require mock objects or some other technique that is not appropriate for CS 2).
Of the three aspects, developing "programming in the large" skills in CS 2 is especially challenging. Our CS 2 course is not an OO analysis and design course, and many students are still novice programmers; therefore, they still need a lot of guidance when given a project. We have struggled to find the right balance between giving the students enough direction to keep them reasonably on track (which has often meant telling them what classes and methods to write) while also keeping the requirements flexible enough to allow them to make non-trivial design decisions (i.e., choose their own classes and methods).
The presence of testing further complicates this balance because in order for an instructor to prepare a set of unit tests that will run against all student submissions, she must require that the students implement a well-defined interface. However, providing an interface limits the students' freedom to make design decisions.
We have discovered that a design process called Presenter First, combined with the idea of specifying package-level (as opposed to class-level) interfaces have helped us find this balance.
Presenter First is a design technique developed by Atomic Object, a software development company in Grand Rapids, Michigan. It is a process of iteratively implementing user stories using a variant of the Model-View-Presenter (MVP) design pattern. MVP organizes application code into three main pieces:
The project writeup contains a more detailed overview of MVP
Students often feel overwhelmed by projects and don't know where to begin. Presenter First provides a clear starting
point: User stories. Students develop a story of the form "When the user xxxx
,
then yyyy
."
An example story would be "When a user clicks on a game square, then a new token should appear in that square."
The MVP design pattern is useful because the presenter provides a single, well-defined place for the code that implements a user story. In particular, students implement a user story by implementing a private method in the presenter that
xxxx
,yyyy
to happen, thenThe complete project description contains a more detailed example.
Notice that it is the presenter, not the view, that detects and responds to UI events. This design helps students by separating their "story" code from the basic UI implementation (which, in Java, can get quite messy). Given a moderately complex GUI with several classes and a more traditional model-view design, the user stories can get spread over several view classes. With MVP, all the user story code remains in the presenter. This design also allows instructors to provide GUI code for a project without requiring students to modify the GUI code. In other words, the students implement the listeners and place them in the presenter they write instead of having to modify the instructor-provided view code.
To further direct students we also provide a package-level interface. We require the students to put their model, view, and presenter code in separate packages. We then prepare a Java interface for the model and specify that
Setting up this "package-level" interface provides the students with guidelines for how to organize their model but also gives them the responsibility and freedom to define any needed helper classes. For example, when implementing a board game, the model often has a class to represent the game board and a class to represent the individual cells on the board. It is the student's responsibility to recognize the need for a "Cell" class and to decide what methods this cell class should implement. We believe that the experience designing these two or three "back-end" classes in the model, as well as implementing the useful private methods in the main model class provides the right amount of "programming in the large" experience for our CS 2 students.
Instructors can write unit tests based on the model interface. Not only does this improve grading, but there are times when running prepared unit tests can help an instructor help a student find a subtle bug. (Note: We use unit tests as a tool to help us find bugs in student code. We still carefully examine the student's code for style, design, comments, etc.)