Code Style Guide

As programmers, your job is not just to write programs that function as expected, but to write code that is efficient, readable, and maintainable.

Benefits of clean code:

The following style guide outlines tips and rules for how you should write code in CS111; some of these guidelines will be used when evaluating code you write in this course.

Table of Contents

Line length

For both readability and to limit complexity, code should not stretch beyond 80 characters long. If you think you need to use more than 80 characters, you are probably trying to do too much in one line of code, and should try to break up that line into multiple shorter lines.

In Thonny, you can set the "Recommended maximum line length" value to 80 (in the Editor tab of the Preferences menu; under Thonny -> Preferences on Mac) to display a thin gray line that will help remind you of this limit.

Sometimes, you may need to work with long strings that challenge this line limit, for example:

example = "This is a very long string that describes itself, and which is longer than 80 characters wide in total, so it does not fit neatly on one line."

Here are several solutions to this problem:

Solution 1) Break the string construction into several lines:

example = (
    "This is a very long string that describes itself,"
  + " and which is longer than 80 characters wide in total,"
  + " so it does not fit neatly on one line."
)

(Note where the spaces are placed inside the quotes! Also note that the parentheses are necessary here to tell python that all of these lines belong together as part of one big expression)

Solution 2) Add line breaks to the code with Python’s line continuation character, a backslash. (Note: You can’t have any characters following the backslash, not even a blank space)

example = "This is a very long string that describes itself, and which \
is longer than 80 characters wide in total, so it does not fit neatly on \
one line."

Solution 3) Use Python“multi-line” strings via triple quotes:

example = """
This is a very long string that describes itself, and which
is longer than 80 characters wide in total, so it does not fit neatly on
one line.
"""

Note in solution #3, the value of the variable will be different than in solutions #1 or #2, because the line breaks in the triple-quoted string will be part of the value of the expression, and they will show up when you print it out. Sometimes this is desirable!

Naming conventions

Naming things well is difficult, but important and rewarding. As you write code, you will have to come up with names for the variables, functions, and parameters that you define, and this has a big impact on code style. Consider which of these two lines of code is easier to follow (both compute the same value)?

Poor variable names:

a = 4/3 * b * c**3

Concise, descriptive variable names:

ballVolume = 4/3 * pi * ballRadius**3

In Python, variable names have some restrictions:

Additionally, we won't use underscores when naming our own variables in this class. When naming multi-word variables this course uses a convention called lower camelCase which means that the first letter of the word is lowercase, and any subsequent word is capitalized.

Example: firstName or maxClassSize

Variable names

Consider this example, which demonstrates poor variable names:

r1 = 100
r2 = 10
d = 50

circle(r1)
lt(90)
leap(r1/2)
rt(90)
leap(-d/2)
circle(r2)
leap(d)
circle(r2)

The variable names r1, r2, and d are generic, repetitive, and non-descriptive. Without further context or comments, it would be hard for a classmate or instructor to know what you were drawing. Now contrast those names to these:

faceRadius = 100
eyeRadius = 10
eyeSeparation = 50

circle(faceRadius)
lt(90)
leap(faceRadius/2)
rt(90)
leap(-eyeSeparation/2)
circle(eyeRadius)
leap(eyeSeparation)
circle(eyeRadius)

Much clearer! Someone scanning your code for the first time would more quickly grasp what you're drawing, without needing to carefully inspect the numbers.

Now, it may seem like a chore to type out those longer variable names again and again in your code, but thankfully an editor designed for code like Thonny includes a solution to this problem: You can press the Tab key after typing the first few letters of a variable name, and the rest of the name will be inserted automatically, or if there are multiple possibilities, you'll be given a menu to choose from. Not only does this save keystrokes, it also means that you won't accidentally misspell your variable names, which can cause problems for your code.

Function and parameter names

All the above guidelines for variables also apply when naming functions and parameters (we'll cover functions in the second week of class).

Bad:

def calc(a, b):
    return a * float(b)

Good:

def calculateTip(bill, tipPercent):
    return bill * float(tipPercent)

These two functions produce the same results, but the latter example is easier to understand at a glance.

Comments

Comments should explain what is not obvious from the code itself.

Here's an example of unnecessary comments:

# Create a filled black circle with a radius of 75
color("black")
begin_fill()
circle(75)
end_fill()
# turn left
lt(90)
# move forward a bit
leap(10)
# turn right
rt(90)

# Create a filled yellow circle with a radius of 75
color("yellow")
begin_fill()
circle(75)
end_fill()

Why? There's nothing these comments add that can't be inferred from reading the code itself. Contrast that to this next example, which provides extra context/explanation that is not immediately apparent from the code itself:

# Create a black circle for the smile
color("black")
begin_fill()
circle(75)
end_fill()

# Move up a bit without drawing a line
lt(90)
leap(10)
rt(90)

# Create a filled yellow circle overlapping the black one so that a
# crescent shape remains for the smile
color("yellow")
begin_fill()
circle(75)
end_fill()

There's a caveat to these commenting guidelines in a course setting such as this— when learning, you can be a little more liberal in your use of comments to explain what code is doing if it's useful for your own reference, for example:

# A negative radius turns right
circle(-75)

Or:

# Integer division always produces an integer result
average = studentCount // 4

To an experienced Python programmer, the comments in the above two examples aren't necessary, but for a beginner they can be valuable.

Comments to organize code

You can/should use comments to organize code into logical parts, like headings in a paper. For example:

# Get price from user
basePrice = input("What is the total menu price of your order? $")
basePrice = float(basePrice)

# Compute tax
tax = 0.0625 * basePrice
totalPrice = basePrice
totalPrice += tax

# Compute tip
tip = 0.18 * basePrice
totalPrice += tip

# Display total result
priceStr = '$' + str(round(totalPrice, 2))
print("Your total price including 6.25% tax and 18% tip will be:", priceStr)

Commenting out code

It can be useful to leave “commented out” code in your work to refer back to later, or provide context for solutions you attempted that did not work as expected.

For example:

# I tried to accumulate the minor players using list comprehension
# but kept getting a invalid syntax error and I can't figure out why

# minors = [player if player['age'] < 18 for player in team]

# Alternatively, I used a for loop:
minors = []
for player in team:
    if player['age'] < 18:
        minors.append(player)

What this commented out code tells us: You didn't arrive at the ideal solution, but you found a working alternative. It can also serve as a reminder for yourself that you need to clarify something about the assignment with an instructor/tutor.

At the same time, code files can get excessively cluttered with old “commented out” code that is no longer needed and provides little to no value.

For example:

#for players in team:
#for player in team:
#if player['age'] < 18
#        minors.append(player)
#
#if player['age'] <= 18
#        minors.append(player)

minors = [player for player in team if player['age'] < 18]

Here we see some ill-formatted attempts with a for loop, followed by a working solution that uses list comprehension (Note: we'll cover for loops and list comprehensions a few weeks into the class). In this case, the commented out code is most likely more distracting than it is useful, and it could be cleaned up before submission.

There's no hard rule when deciding what “commented code” should be left in a finished product— try to strike a balance and ask yourself:

Aside: You can quickly comment/uncomment multiple lines of code using a keyboard shortcut in Thonny (cmd + 3 on a Mac).

Comment Styles

“Inline”-style comments are written next to the code, for example:

x = 5  # Compensate for border

Block style comments precede a line of code, for example:

# Compensate for border
x = x + 1

Inline style comments can help make your code more compact allowing you to see more of your program on the screen at a time. However, inline style comments should only be used for very brief comments, as longer comments will look messy and start to push the 80 chararacter line limit.

The majority of your comments will likely be block style comments.

Docstrings

A “docstring” is a syntax used at the start of a function for documentation purposes; docstrings should be surrounded in triple double-quotes.

Every function that you write must include a docstring describing what it does, and every function that we supply you with will also include one.

Example:

def hop(dist):
    """
    Lifts the pen and moves the given distance to the left of the current
    turtle position without changing the orientation of the turtle (hops
    sideways). Use a negative number to hop to the right. Puts the pen
    back down when it's done if the pen was down beforehand.
    """
    downNow = isdown()
    penup()
    lt(90)
    fd(dist)
    rt(90)
    if downNow:
        pendown()

Docstrings help to quickly summarize what a function does, making code easier to scan.

It also provides for quick reference- in Python if you invoke help(addDonut) (or whatever the function name in question is) in the console, it will show you the docstring.

Tip: all of the functions in starter code that we supply to you have docstrings, which you can view using help, even the functions that are in files you import, like turtleBeads.py.

Keep things tidy

Aim to be consistent with word and line spacing. Here's an example that fails at consistency:

firstName= raw_input('What is your name?')

birthYear =     raw_input('What is your birth year?' )

age=2017-birthYear

print ('Hello ' + firstName + ' you are approximately ' + age + ' years old.')

Contrast that same code to this example:

# Gather details from user
firstName = raw_input('What is your name?')
birthYear = raw_input('What is your birth year?')

# Handle results
age = 2017 - birthYear
print('Hello ' + firstName + 'you are ' + age + 'years old (give or take)')

Abstract solutions

Abstract code solutions save time, allowing your program to more easily adapt to changes. In this context, “abstract” really means “flexible,” because making a concrete value into a variable allows your code to more easily adapt to different situations.

For example, in one of the examples above, we calculated price using tax and tip percentages like this:

# Get price from user
basePrice = input("What is the total menu price of your order? $")
basePrice = float(basePrice)

# Compute tax
tax = 0.0625 * basePrice
totalPrice = basePrice
totalPrice += tax

# Compute tip
tip = 0.18 * basePrice
totalPrice += tip

# Display total result
priceStr = '$' + str(round(totalPrice, 2))
print("Your total price including 6.25% tax and 18% tip will be:", priceStr)

This code works, but what if the tax amount changes from year to year, or you're running the code in a different region with a different tax amount, or you want to set the tip amount higher or lower?

The numbers 0.0625 and 0.18 are buried in the middle of the code, and what's worse, they're used both in the code and in a string that's displayed to the user, so you might forget to change them in both places. To make this code more abstract, so that instead of being specific to 6.25% tax and 18% tip, it works for any tax or tip amount, you could write:

# Tax and tip percentages
taxPercentage = 6.25
tipPercentage = 18

# Get price from user
basePrice = input("What is the total menu price of your order? $")
basePrice = float(basePrice)

# Compute tax (divide by 100 because it's given as a percentage)
tax = (taxPercentage / 100) * basePrice
totalPrice = basePrice
totalPrice += tax

# Compute tip (divide by 100 because it's given as a percentage)
tip = (tipPercent / 100) * basePrice
totalPrice += tip

# Display total result
priceString = '$' + str(round(totalPrice, 2))
taxString = str(taxPercentage) + '%'
tipString = str(tipPercentage) + '%'
print(
    "Your total price including", taxString, "tax and", tipString,
    "tip will be:", priceStr
)

Now, if you wanted to change the tax or tip amount, you could do it by changing one number at the very top of the code, and the correct value would be used for both calculating the total price and for what is displayed to the user.

Another example— imagine you're working on a program to manage a sports team; in several places throughout the code, you need to reference the count of players on the team, e.g.:

averagePoints = totalPoints / 25;

A better approach would be to make the 25 dynamic, like so...

averagePoints = totalPoints / len(players);

This way, when the list of players changes from semester to semester, you don't have to hunt down and replace all the instances in which you “hard-coded” the number 25.

Help us help you

When you have the time, organize code before going to help room or an instructor's office hours so we can more efficiently help you. Sometimes, just trying to figure out the best name for a variable can shed light on a problem in your code.