On this page:
Document Structure - General Exercises
General
6.6

The Style

Programs are easier to read and to understand when they are written in a familiar style and follow standard coding conventions. Most organizations that develop software therefore require programmers to write programs that follow the organization’s preferred style and coding conventions. Programs are generally written once, read many times, and edited over and over again. Style conventions help both you and any other programmer using your code (such as your homework partner) to more easily understand what you were thinking when you wrote the code.

In addition to following the design recipe, all code must adhere to the following style guidelines, which are intended to make your code easier to read, debug, and edit. These guidelines will be updated throughout the semester as you learn more so please check back often to make sure you are adhering to them before you submit your homeworks.

Document Structure - General Exercises

  1. Capitalize terms appropriately. Constants should be in all caps with dashes between words (e.g. (define MY-NUMBER-EXAMPLE 10) or (define SUN-IMG (circle 35 "solid" "yellow"))). Function names, structure names, and inputs should be all lower case with dashes between words (this is called kebab-case). For example (define (my-function-name my-input-name) (+ my-input-name 3)). Types of data should be title case (e.g. ThisIsADataType or ThisIsAnotherOne).

  2. Organize your program top-down. This means that when you write a solution that contains multiple functions, the primary function should come first, followed by helpers. The functions should be in order of where they appear in the primary function. For example, the following code is organized top-down:
    ; my-function : Number String -> Number
    ; Add double the string-length to twice the number cubed
    (check-expect (my-function 2 "hi") 20)
    (check-expect (my-function 3 "hello") 64)
    (define (my-function n s)
      (+ (double (cube-num n)) (double-length s)))
     
    ; double : Number -> Number
    ; Computes 2n
    (check-expect (double 4) 8)
    (define (double n) (* n 2))
     
    ; cube-num : Number -> Number
    ; Produces the cube of this number
    (check-expect (cube-num 5) 125)
    (define (cube-num n) (expt n 3))
     
    ; double-length : String -> Number
    ; Produces twice the length of this string
    (check-expect (double-length "goodbye") 14)
    (define (double-length s)
      (double (string-length s)))

    Please note that many of the above helper functions were written solely to illustrate the top-down organization we expect.

  3. Title your exercises. Above every exercise please note which exercise it is. Note this does not apply to project homeworks.

  4. Separate data definitions. Data definitions (and their corresponding examples/templates) should be placed at the beginning of the relevant exercise. Data definitions do not need to be repeated if used in multiple exercises.

General

  1. Use names that make sense with respect to the problem, for your data definitions, field names, functions, constants, and parameters.

  2. Use proper indentation. Use the indentation style of DrRacket in your program. You can go to "Racket" > "Reindent All" to indent your entire file properly. Press tab to reindent the current line, or the currently selected selected portion of your file.

  3. Keep lines narrow. Do not exceed 102 columns for code or comments. DrRacket will show you the current line and column number in the bottom right of the window. You can also use its Edit -> Find Longest Line menu item. Or, you can go to Edit -> Preferences -> Editing -> General Editing, check the Maximum character width guide option and set it to 102.

  4. Do not use dangling parentheses: the closing right-parenthesis should be on the same line as the last expression of your code.

      ;; ------------------------ GOOD

      (define (f l)

        (cond [(empty? l) 0]

              [else (f (rest l))])) ;; HERE

      ;; ------------------------ BAD

      (define (f l)

        (cond [(empty? 1) 0]

              [else (f (rest l))]

         ) ;; NOT HERE

       )

    The dangling parentheses in the second code excerpt are considered extremely bad style.

  5. Break lines to break up logically distinct tasks. Consider these examples of simple function calls:

      ;; ----------------- GOOD

      (define (foo x y z)

        (max (* x y)      ;; Break after each argument to max,

             (* y z)      ;; and align all arguments in a column

             (* x z)      ;; (This works best with short-named functions)

             (* x y z)))

      ;; ----------------- OK

      (define (foo x y z)

        (max          ;; Break after max itself

         (* x y)      ;; Then indent each argument 1 space

         (* y z)      ;; (This works better when function names are long)

         (* x z)

         (* x y z)))

      ;; ----------------- BAD

      (define (foo x y z)

        (max (* x y)

         (* y z)     ;; This indentation is an inconsistent

         (* x z)     ;; mix of the previous two styles

         (* x y z)))

      ;; ----------------- BAD

      (define (foo x y z)

        (max (* x y) (* y    ;; This linebreak is just weird.

                        z)

             (* x z) (* x    ;; This is ugly. And avoidable!

                        y

                        z)

                        )

                        )

    By breaking after each argument, you will more often keep complete expressions together, and need fewer line breaks overall.

    In rare cases, you can keep two arguments on a line, when they logically belong together. For example, the x- and y-coordinates in a call to place-image might easily fit on one line, and logically form a pair of coordinates, and so could stay on one line in good style.

    Here are some more examples:

      ;; ---------------- BAD

      (define            ;; Don't break here

        (foo x y z)

        ...)

      ;; ---------------- BAD

      (define-struct      ;; Don't break here

        foo [x y z])

      (define-struct foo  ;; or here

        [x y z])

      ;; -------------------------- GOOD

      (define (foo l)

        (if (some-condition ...)

            (then-expression ...)

            (else-expression ...)))

      ;; -------------------------- BAD

      (define (foo l)

        (if (some-condition ...)

          (then-expression ...)    ;; Not aligned with condition

          (else-expression ...)))

      ;; --------------------------------- VERY GOOD

      (define (f l)                        ;; Aligning the responses

        (cond [(empty? l)  0]              ;; in a column is very legible.

              [else        (f (rest l))])) ;; ...if there's room for it

      ;; --------------------------------- GOOD

      (define (f l)

        (cond [(empty? l) 0]

              [else (f (rest l))]))

      ;; --------------------------------- GOOD

      (define (f l)

        (cond

          [(empty? l) 0]

          [else (f (rest l))]))

      ;; --------------------------------- OK

      (define (f l)

        (cond

          [(empty? l)

           0]                    ;; Only use this style if necessary

          [else

           (f (rest l))]))