Upload
baidu-inc
View
12.521
Download
3
Embed Size (px)
Citation preview
The Art of Readable CodeSimple and Practical Techniques for Writing Better Code
Code Should Be Easy to Understand
for (Node* node = list->head; node != NULL; node = node->next) { Print(node->data); }
Node* node = list->head;if (node == NULL) return;while (node->next != NULL) { Print(node->data); node = node->next;}if (node != NULL) { Print(node->data);}
(_=[_=[]][(_+!![])[$=(!!_/!!_)]+(!!$+_)[-~-~$]+'v'+(!(_/_)+[])[-~-~$]+(!([]/($))+[])[$]+([]+!_)[-~-~$]+(!!{}+[])[-~-~$]])()[(!({}+_)+_)[$]+(!({}+[])+[])[-~$]+((''+!![]+''))[-~-~$]+(!![]+'')[$]+((!!_+[]))[$-$]]($/$);
alert(1)
Key Idea
• Code should be easy to understand.
• Minimize the time it would take for someone else to understand it.
Is Smaller Always Better?
Conflict with Other Goals?
Code EfficientWell-Architected
Easy to Test
Highly Maintainable…
Three Levels
• Surface Level
• Loops & Logic
• Reorganizing
Surface-Level
Packing Information into Names
• Specific
• Avoid Generic Names
• Prefer Concrete Names
• Extra Information
• Length vs Meaning
• Formatting
Word Alternative
send deliver, dispatch, announce, distribute, route
find search, extract, locate, recover
start launch, create, begin, open
make create, set up, build, generate, compose, add, new
Naming Conventions
• Noun for variable name, object name, class name, property name, arguments name
• Verb for function name, method name
CasemaptypeCtrl.streetMapMgr(true);
maptypeCtrl.showStreetMap();
A Better One
Length
• Shorter names for shorter scopes
• Longer names for larger scopes
Names That Can’t Be Misconstrued
Key Idea
• Asking yourself, “What other meanings could someone interpret from this name?”
• Prefer min and max for(inclusive) limits
• Naming booleans
• Matching expectations of Users
Casevar read_password = true;
var need_password = true;
var user_authenticated = true;
A Better One
Casemap.getBestMap(points);
map.setViewport(points);
A Better One
Aesthetic
Aesthetic
• Use consistent layout.
• Make similar code look similar.
• Group related lines of code into blocks.
Knowing What to Comment
Key Idea
• The purpose of commenting is to help the reader know as much as the writer did.
What NOT to Comment
• KEY IDEA:Don’t comment on the facts that can be derived quickly from the code itself
Case!
// 延时关闭信息窗⼝口
setTimeout(function(){
map.closeInfoWindow();
}, 100);
Case!
// 添加为全局对象;window.mapSubway = me;
Recording Your Thoughts
• Include “Director Commentary”
• Comment the Flaws in Your Code
• Comment on Your Constants
Put Yourself in the Reader’s Shoes
• Anticipating Likely Questions
• Advertising Likely Pitfalls
• “Big Picture”
• Summary
Precise & Compact Comments
• Keep Comments Compact
• Describe Function Behavior Precisely
• Use Examples
• State the Intent
Case// 返回⽂文件⾏行数int CountLines(string filename) {...}
A Better One// 计算换⾏行符'\n'的个数int CountLines(string filename) {...}
Caseif (mode == "bustime") { var a = minutes % 10, b = parseInt(minutes / 10); minutes = a != 0 ? (a > 5 ? (++b * 10) : b ? (b * 10) : 5): minutes;
Need Examples!
Loops & Logic
Making Control Flow Easy to Read
KEY IDEA
• Make your logic as “natural” as possible
Case
if (length >= 10)
if (10 <= length)
while (bytes_received < bytes_expected)
while (bytes_expected > bytes_received)
Order of if/else Blocks
• Positive First
• Simpler First
• Interesting First
?: Conditional Expression
• Often Less Readable
KEY IDEA
• Minimize the time needed for someone to understand it instead of minimizing the number of lines.
ADVICE
• Use ternary ?: only for the simplest cases.
• Avoid do/while Loops
• Returning Early form a Function
• Minimize Nesting
• Flow of Execution
Breaking Down Giant Expressions
• Explaining Variables
• Summary Variables
• Use De Morgan’s Laws
• Break Down Giant Statements
Case
if (line.split(':')[0] == 'admin')
var userName = line.split(':')[0]; if (userName == 'admin')
Case
if (navigator.userAgent.indexOf('UC') > -1)
if (navigator.userAgent.indexOf('UC') == -1)
var isUC = navigator.userAgent.indexOf('UC') > -1;
if (isUC)
if (!isUC)
Casevar update_highlight = function (message_num) {
if ($("#vote_value" + message_num).html() === "Up") {
$("#thumbs_up" + message_num).addClass("highlighted");
$("#thumbs_down" + message_num).removeClass("highlighted");
} else if ($("#vote_value" + message_num).html() === "Down") {
$("#thumbs_up" + message_num).removeClass("highlighted");
$("#thumbs_down" + message_num).addClass("highlighted");
} else {
$("#thumbs_up" + message_num).removeClass("highighted");
$("#thumbs_down" + message_num).removeClass("highlighted");
}
};
var update_highlight = function (message_num) {
var thumbs_up = $("#thumbs_up" + message_num);
var thumbs_down = $("#thumbs_down" + message_num);
var vote_value = $("#vote_value" + message_num).html();
var hi = "highlighted";
if (vote_value === "Up") {
thumbs_up.addClass(hi);
thumbs_down.removeClass(hi);
} else if (vote_value === "Down") {
thumbs_up.removeClass(hi);
thumbs_down.addClass(hi);
} else {
thumbs_up.removeClass(hi);
thumbs_down.removeClass(hi);
}
};
Variables
Problems
• More variables, harder to keep track of them
• Bigger variable’s scope, longer you have to keep track of them
• More often variable changes, harder to keep track of its current value
Eliminating Variables
• Useless Temporary Variables
• Eliminating Intermediate Results
• Eliminating Control Flow Variables
Casevar remove_one = function(array, value_to_remove) { var index_to_remove = null; for (var i = 0; i < array.length; i ++) { if (array[i] === value_to_remove) { index_to_remove = i; break; } } if (index_to_remove !== null) { array.slice(index_to_remove, 1); } }
Case
var remove_one = function(array, value_to_remove) { for (var i = 0; i < array.length; i ++) { if (array[i] === value_to_remove) { array.slice(i, 1); return; } } }
Shrink the Scope
• Make variable visible by as few lines of code as possible.
Prefer write-once variables
• KEY IDEA: The more places a variable is manipulated, the harder it is to reason about its current value.
Reorganizing
Extracting Unrelated Subproblems
Casefunction findClosestLocation(latLng, latLngs) { var closest; var closest_dist = Number.MAX_VALUE; for each latlng in latLngs, calculate the distance, if new distance is shorter than current, set closest to the new latlng return closest; }
What is the unrelated subproblem?
Compute the spherical distance
• Pure Utility Code
• General-Purpose Code
• Project-Specific Functionality
• Simplifying an Existing Interface
Case
setCookie(key, value);
getCookie(key);
deleteCookie(key);
hasCookie(key);
Cookie
Further Reading
One Task at a Time
KEY IDEA
• Code should be organized so that it’s doing only one task at a time.
Turning Thoughts into Code
• Describe what code needs to do, in plain English(we should use Chinese)
• Pay attention to key words and phrases
• Write your code to match description
Case$is_admin = is_admin_request(); if ($document) { if (!$is_admin && ($document['username']) != $_SESSION['username'])){ return not_authorized(); } } else { if (!$is_admin) { return not_authorized(); } } // continue rendering the page ...
Caseif (is_admin_request()) { // authorized } elseif ($document && $document['username']) != $_SESSION['username'])) { // authorized } else { return not_authorized(); } // continue rendering the page ...
Writing Less Code
KEY IDEA
• The most readable code is
NO CODE AT ALL
Case
• Calculating Distance Between Two Locations
• Don’t implement code that you won’t need
• Simplify requirements
• Keep your codebase small
• Be familiar with Libraries around you
Further Reading
Further Reading
Further Reading
Q&A