the art of readable code (ch1~ch4)

42
The Art of Readable Code (Ch1~Ch4) Jonghan Seo

Upload: ki-sung-bae

Post on 11-May-2015

279 views

Category:

Software


0 download

DESCRIPTION

The art of readable code 팀세미나 발제자료

TRANSCRIPT

Page 1: The art of readable code (ch1~ch4)

The Art of Readable Code (Ch1~Ch4)

Jonghan Seo

Page 2: The art of readable code (ch1~ch4)

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

Page 3: The art of readable code (ch1~ch4)

What Makes Code “Better”?● sometimes it is fairly obvious

Page 4: The art of readable code (ch1~ch4)

What Makes Code “Better”?● sometimes it is vague

more compact !!!

less intimidating !!!

Page 5: The art of readable code (ch1~ch4)

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

Page 6: The art of readable code (ch1~ch4)

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

Page 7: The art of readable code (ch1~ch4)

● 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

Page 8: The art of readable code (ch1~ch4)

Ch2. Packing Information into Names● Key Idea: Pack information into your names

● Six Specific Topics1. Choosing specific words2. Avoiding generic names (or knowing when to use them)3. Using concrete names instead of abstract names4. Attaching extra information to a name, by using a suffix or prefix5. Deciding how long a name should be6. Using name formatting to pack extra information

Page 9: The art of readable code (ch1~ch4)

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()

Page 10: The art of readable code (ch1~ch4)

1. Choose Specific Words

Page 11: The art of readable code (ch1~ch4)

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

Page 12: The art of readable code (ch1~ch4)

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

Page 13: The art of readable code (ch1~ch4)

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.

Page 14: The art of readable code (ch1~ch4)

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

Page 15: The art of readable code (ch1~ch4)

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

Page 16: The art of readable code (ch1~ch4)

4. Attaching Extra Information to a Name● string id; //Example: “af84ef845cd8”

→ string hex_id;

Page 17: The art of readable code (ch1~ch4)

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

Page 18: The art of readable code (ch1~ch4)

● 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?

Page 19: The art of readable code (ch1~ch4)

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);};

Page 20: The art of readable code (ch1~ch4)

● In Javascript:var x = new DatePicker(); // DatePicker() is a "constructor" functionvar 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

Page 21: The art of readable code (ch1~ch4)

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?

Page 22: The art of readable code (ch1~ch4)

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 = 10if shopping_cart.num_items() > MAX_ITEMS_IN_CART: Error("Too many items in cart.")

Page 23: The art of readable code (ch1~ch4)

Prefer first/last for inclusive Ranges

Page 24: The art of readable code (ch1~ch4)

Prefer begin and end for inclusive/exclusive Ranges

Page 25: The art of readable code (ch1~ch4)

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

Page 26: The art of readable code (ch1~ch4)

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()

Page 27: The art of readable code (ch1~ch4)

Matching Expectations of Users

● Example: Evaluating Multiple Name Candidates○ experiment_id: 100

description: ‘increase font size to 14pt’traffic_fraction: 5%…

○ experient_id: 101description: ‘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?

Page 28: The art of readable code (ch1~ch4)

● 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

Page 29: The art of readable code (ch1~ch4)

● ‘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

Page 30: The art of readable code (ch1~ch4)

Ch4. Aesthetics● How good use of spacing, alignment, and ordering can make your code

easier to read

● 3 principles:1. Use consistent layout2. Make similar code look similar3. Group related lines of code into blocks

Page 31: The art of readable code (ch1~ch4)

Rearrange Line Breaks to be Consistent and Compact

Page 32: The art of readable code (ch1~ch4)

Rearrange Line Breaks to be Consistent and Compact

Page 33: The art of readable code (ch1~ch4)

Use Methods to Clean up Irregularity

Page 34: The art of readable code (ch1~ch4)

Use Methods to Clean up Irregularity

Page 35: The art of readable code (ch1~ch4)

Use Column Alignment When Helpful

Page 36: The art of readable code (ch1~ch4)

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

Page 37: The art of readable code (ch1~ch4)

Organize Declarations into Blocksclass FrontendServer { public: FrontendServer(); void ViewProfile(HttpRequest* request); void OpenDatabase(string location, string user); void SaveProfile(HttpRequest* request); string ExtractQueryParam(HttpRequest* request, string param); void ReplyOK(HttpRequest* request, string html); void FindFriends(HttpRequest* request); void ReplyNotFound(HttpRequest* request, string error); void CloseDatabase(string location); ~FrontendServer();};

class FrontendServer { public:

FrontendServer();~FrontendServer();

// Handlersvoid ViewProfile(HttpRequest* request);void SaveProfile(HttpRequest* request);void FindFriends(HttpRequest* request);

// Request/Reply Utilitiesstring ExtractQueryParam(HttpRequest* request, string

param);void ReplyOK(HttpRequest* request, string html);void ReplyNotFound(HttpRequest* request, string

error);

// Database Helpersvoid OpenDatabase(string location, string user);void CloseDatabase(string location);

};

Page 38: The art of readable code (ch1~ch4)

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 Paragraphsdef 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)

Page 39: The art of readable code (ch1~ch4)

Key Idea: Consistent style is more important than the “right” style.

Personal Style vs. Consistency

Page 40: The art of readable code (ch1~ch4)

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○ Be aware of users’ expectation about certain words

Page 41: The art of readable code (ch1~ch4)

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

Page 42: The art of readable code (ch1~ch4)

Q&A

Any Questions?