CSS 162 - Programming Methodology - Spring 2012

Back to homework assignments

Assignment submission guidelines

You will be submitting your programming assignments using the UW Catalyst “Collect It” web submission tool, linked from the course web site. Please submit only .java and documentation files. I will unpack your submission into a directory dedicated to it and compile and test it using a script that applies the same process to everyone’s program. I will also look at your code and read your documentation. It is your responsibility to ensure:

We will also have some written assignments. To ease homework grading and speed return of your work, please follow these homework preparation guidelines for them:

Design and Coding Standards

“If builders built buildings the way programmers wrote programs, then the first woodpecker to come along would destroy civilization.”

“If cars had followed the same developmental path as computers, a Rolls Royce would cost $100, get a million miles per gallon, and explode once a year, killing everyone inside.”

The two quotes above vividly describe the contrast between the typical practice of “programming” and that of other engineering disciplines. What is the difference? Historically, programming was not practiced as an engineering discipline. Practitioners took pride in their ability to hack out solutions. Oftimes, the more elegant solutions were, the harder they were to understand. “If it was hard to write, it should be hard to understand!” was the hacker’s motto.

Much has changed in the last 20 or so years. And one of those changes has been the upgrading of Computer Science to match that of other engineering subjects. Thus, programming becomes Software Engineering, and Software Engineers spend considerable time and effort on activities other than programming. At first blush, this may seem a waste of time. However, nobody would think that of the time spent by a civil engineer designing a building, or an electrical engineer designing a computer. In those other fields, there is a big distinction made between design and construction, with the latter often not considered engineering per se. The same has been increasingly true of software engineering, with software design being engineering and programming becoming coding.

The reasons for this are typically couched in terms of dollars, because the largest consumers of software engineers have been corporations, and it is most convenient for them to convert everything into units of money. However, almost all of the arguments made in favor of this for the corporate environment also apply elsewhere.

The key to to understanding the advantage of the “design first” approach is to consider the entire software life cycle. When you write code without designing it ahead of time (and therefore without any design documents produced), you are making (at least) all of the following assumptions:

  1. That only one person (yourself) will ever have to look at the code.
  2. That the problem is relatively trivial (that you can keep the entire solution in your head, down to the smallest detail).
  3. That the program will be used once, then thrown away (so you won’t have to remember 6 months from now what you did before).
  4. That there will only be one user (so no need to refer to design documentation to answer user questions).

If any of these assumptions are violated, then a design is necessary before any code is written (except perhaps for some prototyping, though there should still be informal designs done for those):

  1. If more than one person needs to write code or work on the design, then a design document is the only way to communicate system function. Code is not documentation, it is implementation. Code does not indicate the function a program is supposed to perform; it only indicates the function that a program actually does perform. Additionally, code is a set of formal instructions meant for a computer, it is an extremely poor way to convey meaning to human beings. Often, it is easier (and faster) to rewrite code than to understand it undocumented.
  2. The solution to any nontrivial problem must be worked out in advance. Systems are often implemented in parts, and inter-operation must be assured. You may need to switch your attention from one part of the system to another, and design documentation is an essential knowledge base for storing what is known about parts you aren’t currently working on.
  3. Six months or more from now, it can be difficult to remember exactly why everything in the code is there. So, not only is design documentation necessary for communication with others, it is also necessary for communication with future versions of yourself.
  4. Oftimes, users will ask questions about software not answered in whatever user guide is produced. At that point, if design documentation is available, an answer may be easily produced. If the answer so arrived at does not conform to the user’s experience with the program, then a bug has been discovered. Therefore, design documentation also helps in the debugging process, allowing you to determine when actual system operation deviates from that which is desired.

“A physician, a civil engineer, and a computer scientist were arguing about what was the oldest profession in the world. The physician remarked, ‘Well, in the Bible, it says that God created Eve from a rib taken out of Adam. This clearly required surgery, and so I can rightly claim that mine is the oldest profession in the world.’ The civil engineer interrupted, and said, ‘But even earlier in the book of Genesis, it states that God created the order of the heavens and the earth out of chaos. This was the first and certainly the most spectacular application of civil engineering. Therefore, fair doctor, you are wrong: mine is the oldest profession in the world.’ The computer scientist leaned back in her chair, smiled, and then said confidently, ‘Ah, but who do you think created the chaos?’ ”

— Grady Booch, Object-Oriented Analysis and Design

Documentation Standards

A simple approach to software development involves two parts before coding: determination of the desired system functionality (specification) and the actual design. The former involves major interaction with the end-users; the latter brings to bear CS knowledge (theory, algorithms, practice) and software engineering technique. We go to this trouble for one simple reason: software systems are the most complex objects routinely constructed by people. A thorough, careful design and development process is the only practical way to manage this complexity. As Grady Booch says, “We observe that this inherent complexity derives from four elements: the complexity of the problem domain, the difficulty of managing the development process, the flexibility possible through software, and the problems of characterizing the behavior of discrete systems.”

Your documentation should be written so that someone else could design and code the program, or understand how your program works (including being able to modify your code).

For this class, your documentation will consist of a specification and a testing report. The specification is your way of ensuring that you understand what the assignment is asking you to do: it makes the program’s functionality precise and detailed. There should be nothing ambiguous or unknown left after you write the specification. Your specification should not just be a regurgitation of the assignment I write; it should instead capture your understanding after all questions you may have are clarified, before you start designing and coding.

Divide your documentation into the following sections:

Problem statement
In your own words, introduce and describe the problem to be solved. This section should also answer the following questions: What assumptions are possible? Are there special cases? Is there anything unclear in the original problem statement given to you that you clarified with me? Any assumptions that you made yourself?
Input data
What is the program’s input data? From where will it come (e.g., a file or the console)? In what format? How does your program know when it has reached the end of its input? What data is valid and what data is invalid? Is there an easily describable range for the data (like a range of integers)? A minimum (or first) value? A maximum (or last) value? Limits on the least (or most) amount of input the program must work on? Good answers here are necessary for development of a test plan, and there should be a clear correspondence between your description of the input and the test sets in your test plan (see below).
Output data
What is the format of the output? Also, consider the questions above for input data.
Error handling
What error detection and error messages are necessary? Is input validation necessary? Do you need to check/guard every I/O operation in case of failure? What about memory allocation failures? What are the warning conditions (where a message is output but program execution can continue) and error conditions (where program execution must end)?
Test Report
The specifications above are the “grist” for your test plan “mill”. Consider the set of possible inputs to your program (defined in the “Input Data” section). Can you break this up into subsets which are similar in some way? For example, if you were writing a tax preparation program, the part that deals with capital gains might treat negative numbers (losses) differently than positive ones (gains). For each of these subsets, choose a small number (perhaps three) of test cases (one good rule of thumb is to use the two boundary elements [largest and smallest values] and one typical value). For each input, determine what the correct output should be. The resulting table of (input, output) pairs is your test plan. Make sure you document the rationale for your test plan; don’t just report the test plan by itself. Do not just produce a plan that tests erroneous input — your test plan should focus primarily on testing the correct operation of your program.

Use this test plan as you incrementally implement your program to check its operation. In your documentation, indicate which tests your program passes and which it fails.

Design and Coding Standards

You are expected to adhere to certain basic principles of good design:

Variables
Each variable (whether it is a primitive type, a composite type [such as an array], or an object) has an associated scope. A variable’s scope may be local to some small block of code (e.g., a loop), local to some function, local for each object (instance variables), or a class variable (static). Instance and class variables can have their accessibility modified by declaring them private or public. You should use the most restrictive scope and access possible for all your variables, i.e., prefer local to instance, which in turn are preferred to class variables. Avoid public class members unless absolutely necessary. You need to justify your design decisions for all class variables and all public class data members.
Methods
A method should perform a single, simply describable operation. If you find that a “method” you are considering really does two things, then it is probably better to make it two methods.
Parameters and return values
One reason for the above definition of methods is that their interfaces are kept small — they have fewer parameters and return values. Monitor each method’s interface complexity. If you are passing/returning many items, this may be a sign that this is not a method.
More about methods
Just like with variables, methods can have private or public accessibility. For each method, you will need to decide whether it should be publicly accessible or not. You should make a method public only if that is truly necessary, based on the definition of the class in question.
Classes and the implementation “wall”
Classes consist of an externally-visible interface (its public members) and a hidden implementation (private members). However, a clever programmer can circumvent the wall around implementation by returning internal, implementation-dependent information. You must not do this — it goes against the purpose of object-oriented design. For example, you may implement a list using arrays or references; under no circumstances should you return any implementation information, such as array indices or node references.
Classes and UI/IO
Classes implementing internal data types should be independent of the exact nature of any particular program. Such classes should not include any user interface operations. As a simple example, imagine you are designing a vector class, and that you included operations tied to a graphical user interface. This would mean that your class would be unusable in a non-GUI environment, such as a computer controlling a car’s engine. You should detach issues of user interface and I/O from such class design — they are separate parts of the design. Implement I/O in classes dedicated to that purpose.

Coding standards means writing code that is easily understood and includes comments that clearly document its function. Code clarity is aided by consistent and useful indentation, identifiers with descriptive names and naming conventions, and the use of language constructs like final. More precisely, our course coding standards are:

Formatting
Blocks of code should be indented three spaces. This includes the bodies of functions. If you use an IDE, make sure it actually writes space characters, not tab characters, into the source files. Limit line length to 80 characters; do not assume that someone reading your code will have a gigantic monitor or good enough eyesight to set a small enough font size to make code with very long lines readable. Assume that the reader will examine your code as plain text files, not using an IDE.
Variables
Variables should be given descriptive names, unless they are very clearly just loop counters or the like. There should be comments associated with each variable declaration explaining how the variable fits into the algorithm, and including invariant information such as its legal range of values.
File comments
Each file should begin with a comment containing the file name, author name, date, and a description of the purpose of the code it contains. The file that contains main() should also include documentation for the overall program: a description of the program’s input and output, how to use the program, assumptions such as the type of data expected, exceptions, and a brief description of the major algorithms and key variables. This is the information you generated in your design, before you started coding. It is expected that you will merely copy the appropriate sections of the your documentation into comments for each file and function (see method comments, below).
Method comments
Each method should be preceded by a comment with a short description of its purpose, arguments, and return values. You are encouraged to use javadoc to format your comments; there is a similar syntax, used by a program called doxygen, for other programming languages.

Last modified: March 26, 2012