2. Ch1. Code Should Be Easy to
Understand
● collected bunch of examples of “bad code”
● analyzed what made them bad
● found principles/techniques that can be used to make them better
● Key Idea: Code should be easy to
understand
4. What Makes Code “Better”?
● sometimes it is vague
more compact !!!
less intimidating !!!
5. The Fundamental Theorem of Readability
● Code should be written to minimize the time it would take for someone
else to understand
● to fully understand your code:
○ be able to make changes to it
○ be able to spot bugs
○ be able to understand how it interacts with the rest of your code
● ‘someone else’ would be you
6. Some Different Views
● The Smaller The Better?
○ It probably takes less time to understand fewer lines BUT it is not
always better!
○ the time-till-understanding is an even better goal
● What about other constraints?
○ code efficiency? well architectured? easy to test? …
○ making code easy to understand often leads to meet the other rules
● the rest of this book discusses how to apply ‘easy to read’ in different
circumstances
7. ● There are four parts:
○ Part One: Surface-Level Improvements
○ Part Two: Simplifying Loops and Logic
○ Part Three: Reorganizing Your Code
○ Part Four: Selected Topics
● Surface-Level Improvements
○ picking good names
○ writing good comments
○ formatting your code neatly
Contents
8. Ch2. Packing Information into
Names
● Key Idea: Pack information into your names
● Six Specific Topics
1. Choosing specific words
2. Avoiding generic names (or knowing when to use them)
3. Using concrete names instead of abstract names
4. Attaching extra information to a name, by using a suffix or prefix
5. Deciding how long a name should be
6. Using name formatting to pack extra information
9. 1. Choose Specific Words
● def GetPage(url): …
○ from a local cache? from a database? from the Internet?
○ FetchPage(), DownloadPage()
● class BinaryTree {
int size();
...
}
○ height of the tree? the number of codes? memory footprint of the tree?
○ Height(), NumNodes(), MemoryBytes()
11. 2. Avoid Generic Names
● ‘tmp’, ‘retval’, loop iterators
● retval
○ var euclidean_norm = function (v) {
var retval = 0.0;
for (var i = 0 ; i < v.length; i += 1)
retval += v[i] * v[i];
return Math.sqrt(retval);
};
○ reval → sum_squares
○ sum_squares += v[i]; → spot a bug!!
○ Advice: Use a name that describes the variable’s value
12. 2. Avoid Generic Names
● tmp
○ if (right < left) {
tmp = right;
right = left;
left = tmp;
} // it is ok!
○ String tmp = user.name();
tmp += “ “ + user.phone_number();
…
template.set(“user_info”, tmp); // tmp → user_info
● Advice: ‘tmp’ should be used in cases when (1) being short-lived and (2)
temporary is the most important fact about the variable
13. 2. Avoid Generic Names
● Loop Iterators
○ for (int i = 0; i < clubs.size(); i++)
for (int j = 0; j < clubs[i].members.size(); j++)
for (int k = 0; k < users.size(); k++)
if (clubs[i].members[k] == users[j])
cout << "user[" << j << "] is in club[" << i << "]" << endl;
○ (i, j, k) → (club_i, memeber_i, users_i) or (ci, mi, ui)
○ if (clubs[ci].members[ui] == users[mi]) // Bug! First letters don't match up.
14. 3. Prefer Concrete Names Over
Abstract Names
● Example1) Google Code Guide for C++
○ #define DISALLOW_EVIL_CONSTRUCTORS(ClassName)
ClassName(const ClassName&);
void operator=(const ClassName&);
class ClassName {
private:
DISALLOW_EVIL_CONSTRUCTORS(ClassName);
};
○ ‘evil’ sounds too strong and more important, it isn’t clear what the
macro is disallowing
○ DISALLOW_COPY_AND_ASSIGN
15. 3. Prefer Concrete Names Over
Abstract Names
● Example2) --run_locally
○ --run_locally
■ printing debugging information
■ used when testing on a local machine
○ What if we need...
■ to print debugging information while the program run remotely?
■ to run a performance test locally (so we do not want the logging
slowing it down)?
○ --run_locally → --extra_logging
16. 4. Attaching Extra Information to a
Name
● string id; //Example: “af84ef845cd8”
→ string hex_id;
17. 5. How Long Should a Name be?
● the implicit constraint: ‘the name shouldn’t be too long’
○ the longer a name, the harder it is to remember and the more space it
consumes on the screen
○ However, if we take the constraint too far it also would make someone
else difficult to understand the code
18. ● There are some guidelines:
○ Shorter names are all right for shorter scope
○ Typing Long Names - Not a Problem Anymore
■ if ‘they’re harder to type’ mattered
■ Make full use of ‘word completion’ built in editors
○ Acronyms and Abbreviations
■ project-specific abbreviations: Bad Idea
■ common to programmers: OK!
● evaluation → eval, document → doc, string → str
○ Throwing out Unneeded Words
■ ConvertToString() → ToString()
■ DoServerLoop() → ServerLoop()
5. How Long Should a Name be?
19. 6. Use Name Formatting to
Convey Meaning
● In C++:
static const int kMaxOpenFiles = 100;
class LogReader {
public:
void OpenFile(string local_file);
private:
int offset_;
DISALLOW_COPY_AND_ASSIGN(LogReader);
};
20. ● In Javascript:
var x = new DatePicker(); // DatePicker() is a "constructor" function
var y = pageHeight(); // pageHeight() is an ordinary function
● in jQuery:
var $all_images = $("img"); // $all_images is a jQuery object
var height = 250; // height is not
● in HTML:
<div id=”middle_column” class=”main-content”>
6. Use Name Formatting to
Convey Meaning
21. Ch3. Names That Can’t Be
Misconstrued
● We have focused on how to put a lot of information into our names.
● We will do on a different topic: watching out for names that can be
misunderstood
● Key Idea: Actively scrutinize your names by asking yourself, “What other
meanings could someone interpret from this name?”
● example: filter()
○ results = Database.all_objects.filter("year <= 2011");
○ what does results now contain?
■ Objects whose year is <= 2011?
■ Objects whose year is not <= 2011?
22. Prefer min/max for (inclusive)
Limits
● CART_TOO_BIG_LIMIT = 10
if shopping_cart.num_items() >= CART_TOO_BIG_LIMIT:
Error("Too many items in cart.")
● MAX_ITEMS_IN_CART = 10
if shopping_cart.num_items() > MAX_ITEMS_IN_CART:
Error("Too many items in cart.")
25. Naming Booleans
● bool read_password = true;
○ We need to read the password: need_password
○ The password has already been read: user_is_authenticated
● adding words like is, has, can or should can make booleans more clear
○ SpaceLeft() → HasSpaceLeft()
● trying to avoid negated terms in a name
○ disable_ssl = false → use_ssl = true
26. Matching Expectations of Users
● Example: get*():
○ get: “lightweight accessors”
○ public double getMean() {
//Iterate through all samples and return total/num_samples
}
○ getMean() → computeMean()
● Example: list::size()
○ in C++, list::size() is an O(n) operation
○ size() → conuntSize(), countElements()
27. Matching Expectations of Users
● Example: Evaluating Multiple Name Candidates
○ experiment_id: 100
description: ‘increase font size to 14pt’
traffic_fraction: 5%
…
○ experient_id: 101
description: ‘increase font size to 13pt’
[other lines are identical to experiment_id 100]
...
○ ‘the_other_experiement_id_I_want_to_reuse: 100’ can be
renamed? If so, how?
28. ● Candidates:
○ template
○ reuse
○ copy
○ inherit
● ‘template’
○ experiment_id: 101
template: 100
○ ‘i am a template’ vs ‘i am using this other template’
○ ‘template’ is generally something abstract that must be filled in
● ‘reuse’
○ ‘This experiment can be reused at most 100 times’
Matching Expectations of Users
29. ● ‘copy’
○ ‘copy this experiment 100 times’ or ‘this is the 100th copy of
something’
● ‘inherit’
○ with inheritance
■ get all features from the inheritee
■ can modify inherited features
■ can add more own features
○ inherit_from_experiment_id might be the best
Matching Expectations of Users
30. Ch4. Aesthetics
● How good use of spacing, alignment, and ordering can make your code
easier to read
● 3 principles:
1. Use consistent layout
2. Make similar code look similar
3. Group related lines of code into blocks
36. Pick a Meaningful Order, and Use
It Consistently
● details = request.POST.get('details')
location = request.POST.get('location')
phone = request.POST.get('phone')
email = request.POST.get('email')
url = request.POST.get('url')
● some meaningful orders:
○ the order of the <input> field on the corresponding HTML form
○ from ‘most important’ to ‘least important’
○ alphabetically
38. def suggest_new_friends(user, email_password):
friends = user.friends()
friend_emails = set(f.email for f in friends)
contacts = import_contacts(user.email, email_password)
contact_emails = set(c.email for c in contacts)
non_friend_emails = contact_emails - friend_emails
suggested_friends = User.objects.select
(email__in=non_friend_emails)
display['user'] = user
display['friends'] = friends
display['suggested_friends'] = suggested_friends
return render("suggested_friends.html", display)
Break Code into Paragraphs
def suggest_new_friends(user, email_password):
# Get the user's friends' email addresses.
friends = user.friends()
friend_emails = set(f.email for f in friends)
# Import all email addresses from this user's email account.
contacts = import_contacts(user.email, email_password)
contact_emails = set(c.email for c in contacts)
# Find matching users that they aren't already friends with.
non_friend_emails = contact_emails - friend_emails
suggested_friends = User.objects.select(email__in=non_friend_emails)
# Display these lists on the page.
display['user'] = user
display['friends'] = friends
display['suggested_friends'] = suggested_friends
return render("suggested_friends.html", display)
39. Key Idea: Consistent style is more important than the
“right” style.
Personal Style vs. Consistency
40. Summary
● Ch2. Packing Information into your names
○ Use specific words
○ Avoid generic names
○ Use concrete names
○ Attach important details
○ Use longer names for larger scopes
○ Use capitalization, underscores, and so on in a meaningful way
● Ch3. Names That Can’t be Misconstrued
○ Use ‘max_/min_’ for an upper or lower limit for a value
○ Use ‘first/last’ for inclusive ranges
○ Use ‘begin/end’ for inclusive/exclusive ranges
○ Use words like is and has to make boolean variables clear
○ Avoid negated terms
41. Summary
● Ch4. Aesthetics
○ Try to give similar codes the similar silhouette
○ Align parts of the code into columns
○ Pick a meaningful order and stick with it
○ Break apart large blocks into logical paragraphs