CS50x2 Grading Guidelines (Causey)

From A-State Computer Science Wiki
Jump to: navigation, search

Introduction

The standards given here specify the manner in which programming projects are to be completed. They are not necessarily the best or only way to do things, but they are the guidelines by which your work will be evaluated. The standards set forth in this guideline should be followed closely as grading will be based on compliance with them.

Recommended Development Process

Be prepared to spend as much time thinking about your solution as you spend actually coding. The more thought and planning you put into it up front, the faster a correct code solution will take shape.

We recommend that you design your programs using a top-down design approach. Start with a high-level, English-like pseudocode describing what your program should do in a (relatively) few broad terms. Then begin to fill in the details necessary to actually perform the high-level steps you have identified — each level of detail in the algorithm should be slightly closer to "code" than the previous. Keep performing this refinement until you have enough "near-code" detail to start translating it into a real program. By avoiding becoming too concerned with fine details too soon, you will reduce the probability of overlooking important considerations that would cause you to have to redesign and rewrite code.

Programs can also be developed using a top-down coding approach; we recommend that you do take this approach whenever possible. Begin coding the "top-level" steps of your algorithm first, creating function stubs as needed as you go, then fill in the "details" in the function bodies later (using the same top-down approach as you do). Compile as early and as often as possible — each time your code reaches a state at which it should compile without syntax errors, try to do so. This will not always be applicable to every program, but when it is it will save you time in correcting syntax and structural errors.

Your programs shall utilize "structured programming" techniques. This means in part that unstructured elements (e.g. break, continue, exit, goto, etc.) are to avoided. Each function shall have one entry point and one exit point; in particular, there should only be a single return point in a function, and it should be at the bottom. The important structured programming rules are listed below.

Style Guidelines

Structural Style

The way you structure your program can affect how easy it is to read and reason about the code. In general, you want to write code that is as easy to read and understand as possible. "Tricky" code should be avoided in favor of simple, straight-forward code; try to imagine how it will read to you after several months have passed without looking at it.

Readability

Some structural decisions can affect the readability of your code:

  • The body of all control structures shall be indented. We recommend 4 spaces per indent level, but any amount from 3 to 5 is acceptable as long as you are consistent.
  • Statements within the same control structure shall be aligned. All statements must start at exactly the same column as the previous statement, unless you are changing indentation levels on purpose.
  • Closing curly braces must align with the first character of the line of code where the block began.
  • Long lines of code must be avoided; you should find a place to break a line longer than about 80 characters; the continuation of the line must be indented to visually show it is a continuation.
    • If you are using indentation to continue a long line, the indented continuation lines must be aligned with one another.
    • This guideline generally does not apply to inline comments; use your judgment to determine whether a comment should be broken to the next line.
  • Use horizontal whitespace (spaces) around operators (i.e. x + y, not x+y) to make expressions easier to read.
  • Use vertical whitespace (blank lines) to separate logical groups of statements within long functions. Related statements will visually appear together, and "phases" of computation will look visually distinct.
  • Avoid "too much of a good thing": Don't use more horizontal or vertical whitespace than necessary; doing so can detract from the readability of the code.
    In particular, do not "double-space" your code.
  • No more than one statement may be placed on a line.

Modularity

(This section applies once you have learned about functions.)
Your code must be designed and implemented to be as modular as possible. Here are some guidelines:
Note: One "screen" of code refers to the amount of code that will fit on the screen of a typical computer monitor; usually between 40 and 60 lines.

  • All functions (including the main function) should consist of at most one screen of code. If the function is longer, it should be broken into sub-functions.
  • Create a function for any logical step that requires more than a few lines of code.
  • If you find yourself repeating sections of code, create a function for that task instead.
    • This important concept is known as the DRY Principle (for Don't Repeat Yourself); it will shrink your program while also making the code easier to read and to maintain.
  • Functions should generally either perform a computation and return a result, or create a side-effect (like output); avoid creating functions that do both.
  • Prefer parameters to hard-coded values; strive to make your functions as general as is reasonable for the scope of the problem you are trying to solve.

Code Correctness

Your code will be graded on "correctness". This implies the following things, some of which are obvious, but some might not be:

  • Your code must compile successfully.
  • The program produced by compiling your code must perform the operations or produce the results specified by the assignment.
  • Your code must consist of Standard C++ statements and patterns. (As defined by the ISO C++ Standards Committee (see the standard here).
    • This can be challenging at times - your compiler will almost certainly allow you to do things that are not permitted under the rules of the standard. Pay attention in class; things that you can and cannot do will be pointed out. If you aren't sure, ask your instructor.
  • Your algorithms must represent a valid approach to solving the problem you are being asked to solve.
    • This one can occasionally be tricky too: Sometimes an incorrect algorithm can produce "correct" results in special cases. A lack of thorough testing may mean that you have logical errors that you are not observing when you run the program.

Structured Programming Rules

The following "rules" are not defined by the C++ language itself, but rather by adherence to the structured programming paradigm.

  • Every function shall have a single entry point and a single exit point, unless a fatal error has occurred.
  • Global variables shall be avoided except in special cases (discuss with your instructor).
    • Global constants are acceptable when necessary (i.e. for fixed array sizes, etc.).
  • Use constants for those values which will not change throughout the execution of the program. Examples might include taxRate, commission, etc.
  • The use of goto and continue is not allowed.
  • break may only be used within a switch control structure.
  • return should appear at most once within a function, at the bottom.
    • All functions with a non-void return type (value-returning functions) must contain exactly one return statement.
    • Non-value-returning functions (i.e. void functions) may omit the return statement (but be consistent in this choice).
  • The use of exit() is allowed only in cases where program continuation is not possible, and where not using exit() would make the structure of the code significantly more complex and difficult to follow.
  • Do not make an equality comparison such as
    a == b
    

    upon variables of a floating-point data type; instead, use a tolerance test such as

    fabs(a - b) < 1e-10
    

Naming Guidelines and Self-Documenting Code

The way you name things can have a major impact on how easy it is to read, understand, and reason about your code. Self-Documenting Code is the concept that when another programmer is reading your code, it will be obvious what the program is doing; no additional documentation is required. Your identifiers (names) should be chosen to be as descriptive as possible. Choose names that "say what they do". It is not always possible to write code that is perfectly obvious, but choosing good identifiers will help tremendously.

Naming and Capitalization

Choose meaningful identifiers that describe their purpose clearly. Avoid creating very short (one or two letter) names unless the name has a well-known meaning while also being short, or a single-letter name is idiomatic for the purpose you are using it for (i.e. a loop counter). Most modern programmer's text editors will have the option of completing names automatically, so repeatedly typing a long identifier need not be a problem.

Additionally, follow the following guidelines for idiomatic C++ identifiers:

  • There are four widely used capitalization patterns for identifiers that are acceptable (in certain circumstances) according to these guidelines:
    • lowerCamelCase - The first letter is lowercase, and the first letter of each additional word is uppercase; no underscores are used (except in special cases as first character).
    • UpperCamelCase - The first letter is uppercase, as well as the first letter of each additional word; no underscores are used (except in special cases as the first character).
    • snake_case - All alphabetical characters are lowercase, with words separated by underscores. (The name is a nod to the popularity of this style in Python programming.)
    • ALL_CAPS - All alphabetical characters are uppercase, with words separated by underscores.
  • Variable, function, and method names shall use either camelCase or snake_case; be consistent in your choice for each type of identifier.
  • Global constants shall be named in ALL_CAPS, or in snake_case.
  • Preprocessor macros shall be named in ALL_CAPS.
  • Avoid using the digit zero '0' in an identifier if it might lead to confusion with the letter 'O'.

Explicit Comments

Even good self-documenting code is not always enough to make your code's purpose (and your reasons for structuring it the way you chose to) obvious. It is impossible for the code itself to convey related context information. Use inline code comments to clarify these parts. Your comments should not repeat what the code already says; instead, you should "tell the story" of the code — explain why you wrote the code the way you did, and what you intend for it to do. This will help other programmers (or yourself, later) understand your intent. This is especially important for debugging a program when the results don't match your intent; comments provide the context to help you find places where your assumptions may have been wrong.

Documentation Guidelines

Structural Documentation

Each part of your program should include documentation explaining its purpose, as well as information about how it should be used, and other useful metadata related to the code. We require that you write your structural documentation in an industry-standard format (known as Javadoc format) so that they could be used by a documentation tool such as Doxygen to generate online or PDF documentation manuals if you chose to do so. You may also use Doxygen's own "backslash" tag syntax, or XML syntax if you prefer.

We require the following structural documentation:

  1. The file containing function main (or other start of execution) shall contain a comment block in the following format:
    Note: example assumes a file called main.cpp. Update all information to reflect your actual program.
    /**
     *******************************************************************************
     * @file    main.cpp
     * @brief   Brief description of what this file contains shall be placed here.
     *
     * More general information about what this program or project will do shall be
     * placed here (the file containing main() is usually the first place a programmer
     * would look for information about a large program with many source files).
     *
     * @remarks
     *      Course:        Computer Science nnnn, Fall/Spring yyyy
     *      Due Date:      e.g. Wednesday, June 30
     *      Instructor:    faculty name
     *
     * @author  your name
     * @date    date you created the file
     *******************************************************************************
    **/
    

    In this case, the @remarks section is used to present information for which there is no specific Javadoc tag, but that is important for keeping our homework organized.
    The lines toward the top and bottom that contain multiple asterisks can be used to help determine line length of the lines as they end at the 80th character position.

    Note: Doxygen comment blocks always begin with /** (the two asterisks here are required).
  2. Each additional file in a project shall contain the following comment block (at a minimum):
    Note: example assumes a file called source_filename.cpp. Update all information to reflect actual file.
    /**
     * @file    source_filename.cpp
     * @brief   Brief description of what this file contains shall be placed here.
     *
     * More general information about what this file contains, and how it is intended
     * to be used shall be placed here, along with any additional information that
     * you feel is relevant.
     *
     * @author  your name
     * @date    date you created the file
     */
    
  3. Each function shall be preceded by a prologue that explains the purpose and a brief description of how to use the function. It shall note if the function performs any external input and/or output. It shall also specify the data flow into and out of the function both by way of the parameter list and return statement. These descriptions shall be addressed to a user who wants to quickly learn how to use the function. The following format shall be used:
    /**
     * @brief       a brief description of what this function does
     *
     * @detailed    A more detailed description of the function should go here, 
     *              along with a description of how the function should be used.
     *
     * @remarks
     *      Use the "remarks" section if there are any additional items a programmer
     *      might need to know about this function.  For example, if the function
     *      performs external input and/or output, describe it here.
     *
     * @param        parameter1     description of parameter1
     * @param        parameter2     description of parameter2
     * @param[out]   parameter3     parameter3 is an output parameter; this its description
     *
     * @return  If the function returns a value, explain what the value is and
     *          how it might be used here.
    **/
    

    Note that you will need one @param tag for each parameter that your function requires. The @param[out] tag indicates an output parameter (a non-const reference parameter in C++). There is also a @param[in] tag for input parameters and a param[in,out] tag for in/out parameters; since an input parameter is the default, you need not use @param[in] unless you are concerned about ambiguity.

    You will not always use all of the tags shown: Use only the ones that you need for the function you are documenting. If your function does not have any parameters, you don't need any @param tags; if your function's purpose is very simple, don't provide both the brief and detailed description (just omit the @brief tag and write the short description); if you don't have any remarks, don't use the @remarks tag; if your function does not return any value, omit the @return tag.

    There are also other tags available. See the full list of possible tags here. (Note: The tags shown are in the Doxygen format, beginning with a backslash; you can replace the backslash with the @ symbol to make them look like Javadoc tags — Doxygen understands both styles.)

In-Code Comments

In addition to the structural documentation required (above), you will also need to write some number of comments directly in the code itself. Here are some reasons that you may choose to write an inline comment:

  • If the name of the variable doesn't completely explain what its purpose is, you might need to add a comment with some added information.
  • Sections of code whose purpose or function isn't immediately obvious after reading the code should be commented; your comment should either precede the code in question, or be placed at the end of the line, to the right of it.
  • Complex control structures can often benefit from added context explaining what would cause execution to end up at the various parts (large if-else chains, for example). Add comments to explain what each part of such a structure is responsible for.
  • Sometimes you will write a code statement that might at first glance appear incorrect, but is actually necessary for correct operation of the algorithm. Add comments to explain this so that you don't remove or edit the statement later and introduce an error.

Examples

Take a look at the following examples that demonstrate concepts discussed above:

Good vs Bad Comments

Good:

    balance = balance + credit;               // apply the deposit to the account

Bad:

    balance = balance + credit;               // balance plus credit

Indentation, Alignment, and Inline Comments

if (inventory > minimum_safe_quantity){       // plenty of items in stock
    cout << "sufficient quantity on hand";
}
else{                                         // not enough inventory
    cout << "place order immediately";
}

The following shows good indentation/alignment, but bad variable naming: What does this code mean?

if (c > 0){
    a = b + c;
    j++;
}

This example shows an alternate placement of the opening curly brace that is also permitted; just be consistent. Also, it shows good indentation/alignment, but bad variable naming, and the code isn't self-documenting — some inline comments are desperately needed.

x = 1;
while (error > 0.01)
{
    y = sqrt (x);
    error = f(x) + g(y) - 7;
    x = x + 10;
}

This example shows a function (complete with required documentation) that performs a Bubble Sort:

/**
 * sorts the values in `list` in-place in ascending order
 *
 * @param[in,out] list          the array of values that will be sorted
 * @param         list_size     the number of values contained in `list`
 */
void bubbleSort(int list[], int list_size){
    for (int i = 0; i < list_size - 1; i++){      // for each pass (n-1 passes required)...
        for (int j = 0; j < list_size - i; j++){  // scan remaining un-sorted part of array...
            if (list[j+1] < list[j]){             // if an pair is out of order...
                auto temporary = list[j];         // swap them.
                list[j]        = list[j+1];
                list[j+1]      = temporary;
            }
        }
    }
}

Breakdown of Credit to Be Assigned to Programs

Programs will be graded according to the following rubric, Causey2011. This rubric is available at Rubric Causey2011.

Instructions

The rubric below defines several programming code assessment categories. Each category contains criteria related to an assessment score in the range of 0-5, with a description of the meaning of that score. The descriptions may include several independent criteria; if so, each is considered sufficient to select a particular point assessment. It is not necessary that all criteria be met to receive a particular assessment. Independent criteria will be separated by periods, dependent criteria will be separated by semicolons. Not every category will be appropriate for every programming assignment, so individual assignments may not be assessed in one or more category; categories may also be independently weighted to provide emphasis on featured skills in an assignment. Information about category weighting should be made available along with other assessment feedback.

Program Correctness Criteria

[O] Output Correctness

+5 Correct: Expected output is produced for all test cases.
+4 A single error or very minor errors in expected output.
+3 Few errors in expected output.
+2 Many errors in expected output.
+1 Output is only correct in special or single case.
+0 No output, completely incorrect output, or did not compile.

[C] Code/Algorithm Correctness

+5 Algorithm is functionally correct; no logic errors for test conditions.
+4 A single error or very minor errors in code/algorithm, may or may not have affected test cases.
+3 Few errors in code/algorithm, affecting one or more test cases.
+2 Many errors in code/algorithm, affecting most test cases.
+1 Code/algorithm is only correct in special or single case.
+0 Did not compile or completely incorrect functionality, logic, or algorithm. Program does not demonstrate a solution to the problem as assigned.

[T] Testing Rigor

+5 Tests are thorough and exercise all boundary conditions; testing provides positive assurance that no algorithm or logic errors are present.
+4 A single or very minor omissions in test conditions; testing is sufficient for all likely states of the algorithm.
+3 Few omissions in test conditions, omitting one or more likely states of the algorithm. Some boundary conditions not checked.
+2 Tests omit many possible conditions. Many redundant tests examine the same conditions with no contribution to algorithm quality. No thought given to boundary conditions.
+1 Testing only provides assurances for the most common or "perfect world" states of the algorithm.
+0 No testing code was provided, or tests were inadequate to provide any assurance of correctness, or did not compile.

User Interface Criteria

[Q] Output Quality

+5 Excellent output format; very visually compelling; exceeds output requirements.
+4 Good output format; somewhat visually compelling; meets output requirements.
+3 Mostly correct output format; not visually compelling.
+2 Some errors in output format; fails to meet requirements.
+1 Significant errors in output format; items are hard to identify.
+0 Output items lack all formatting and cannot be identified, or did not compile.

Code Quality Criteria

[S] Coding Style

+5 All identifiers are descriptive and follow naming conventions; style and punctuation guidelines are observed; simple and elegant program constructs; program layout, indentation, and separation are consistent and attractive; source code is highly readable; no required functionality is omitted or left as a stub.
+4 Naming, style, and punctuation are mostly correct and consistent, but occasional errors are found; program constructs are appropriate; program layout, indentation, and separation are generally consistent; Exceptions do not affect readability; no or a negligible amount of required functionality is omitted or left as a stub.
+3 Naming, style, and punctuation are generally correct and consistent, but several errors are found. Program constructs are appropriate but could have been simplified. Program layout and indentation are acceptable, though inconsistencies affect readability. Few procedures are stubs lacking required functional code.
+2 Inconsistent punctuation and naming of identifiers make code difficult to follow. Program constructs are inappropriate. Program layout and spacing are generally inconsistent and affect source code readability significantly. Some procedures are stubs lacking significant functional code.
+1 Naming, style, and punctuation guidelines are generally ignored. Program constructs are unnecessarily complex. Minimal attention is given to layout, indentation, and separation. Horizontal and vertical spacing are mostly nonexistent. Selections of code are very difficult to read. Many procedures may be stubs lacking functional code.
+0 Naming is inconsistent and misleading. No punctuation guidelines are observed. Program constructs are excessively complex, requiring significant effort to comprehend. No considerations are given to layout, indentation, and separation. Program is unreadable. Functional code is nonexistent, or only shell code is provided; not enough functional code to judge style criteria.

[D] Documentation

+5 Documentation is exemplary and provides accurate information at an appropriate level of details; all required elements are present and follow the prescribed format; new information is added by the in-code comments.
+4 Documentation is correct and mostly complete but not compelling. While the prescribed format is used, details may be lacking in some instances. Some in-code comments may not add new information.
+3 Documentation follows the prescribed format but includes needed elements at a level that is too general; details are lacking in some instances. In-code comments may be somewhat sparse or fail to provide new information.
+2 Documentation is acceptable but ignores the prescribed format and may lack one or more required items. Difficult sections of code lack comments. Missing functional code severely reduces the available in-code documentation that can be judged.
+1 Documentation is minimal and uses an incorrect format. Few, if any, in-code comments are given; those that are present rarely impart new information. Not enough functional code to judge in-code documentation.
+0 The source code contains no documentation.

Information About Grading Feedback

Not all categories from the rubric will be used to grade every assignment. During grading, a grading overview header will be placed at the top of the file containing your main() function (or if no main function is included, at the top of one of the source files). An example of the grading overview header is shown below. Notice that the number of points earned in each of the rubric categories is listed in the header. Any categories not used will be left blank.

Other comments related to grading will be placed below the header and throughout the code. You can easily find the grader comments because they will all begin with the //~*GRADER NOTE*~: mark. Where applicable, a rubric category code (such as [C]) will be included in the comment to let you know which rubric category the the comment relates to.

Special Grading Considerations

In addition to the score earned by grading against the rubric above, other factors may contribute to the final points earned for a program. These include the following; other considerations may exist as well, on a case-by-case basis:

  • Program submitted late:
    • 1 day late (denoted by code [L1]):
      10% is deducted from the points earned after grading.
    • 2 days late (denoted by code [L2]):
      30% is deducted from the points earned after grading.
    • 3 days late (denoted by code [L3]):
      50% is deducted from the points earned after grading.
    • More than 3 days late (denoted by code [L+]):
      A score of zero is assigned for the program. Grader comments may still be included in the code.
  • Program does not compile (denoted by code [DNC]):
    In this case, any rubric category that requires a running program cannot be evaluated, and will receive a 0. This include categories O, Q, C, and T. No attempt will be made to "fix" a program that does not compile in order to grade it. You are responsible for verifying that the program works before submitting your source code. (In certain special cases, if a single minor "fix" is all that is required, the "fix" may be applied and a fixed deduction (10-50%) may be taken from the overall score; at the discretion of the grader.)
  • Program does not solve the problem assigned, or shows completely incorrect functionality (denoted by code [NCF]):
    Treated the same as if the program did not compile. See above.
  • Program is found to be plagiarized, in full or in part (denoted by code [PLAG]):
    A score of zero is assigned for the program. Further action may be taken by the Department of Computer Science and/or the University

Example of Grading Overview Header

//~Student:
//~~~~~~~~~~~~~~~~THIS HOMEWORK HAS BEEN GRADED~~~~~~~~~~~~~~~~~
//~~SEE ADDITIONAL INFO BELOW IN LINES MARKED //~*GRADER NOTE*~:


//~GRADING CRITERIA (each category ranked 0-5)
//~For more info, see:
//~  http://wiki.cs.astate.edu/index.php/Rubric_Causey2011
//~
//~Output Correctness `[O]:
//~Output Quality     `[Q]:
//~Algor. Correctness `[C]:
//~Testing Rigor      `[T]:
//~Style/Clarity      `[S]:
//~Documentation      `[D]:
//~
//~Other Considerations   :
//~Pts. Possible          :
//~Pts. Earned            :