The Art Of Readable Code
Transcript of The Art Of Readable Code
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