首页 > 代码库 > 读书笔记之《The Art of Readable Code》Part 3

读书笔记之《The Art of Readable Code》Part 3

如何重新组织代码提高可读性? (函数层面, part 3)
1. 抽取与主要问题无关的代码
2. 重新组织代码使得一次只做一件事
3. 首先描述功能,然后再实现功能,这样更清楚明了

如何抽出问题无关的子问题? (chap 10)
0. 无关问题的思考
 - 看到一个函数或一个代码块, 问自己, "这段代码的高层作用是什么(high-level gloal)"
 - 对于每一行代码, 思考"它是直接解决这个目标吗",还是"解决一个子问题来达到目标的解决"
 - 如果是解决子问题,并且代码的行数也足够多,那么就可以抽取出一个独立的函数

// Return which element of ‘array‘ is closest to the given latitude/longitude.// Models the Earth as a perfect sphere.var findClosestLocation = function (lat, lng, array) {    var closest;    var closest_dist = Number.MAX_VALUE;    for (var i = 0; i < array.length; i += 1) {        // Convert both points to radians.        var lat_rad = radians(lat);        var lng_rad = radians(lng);        var lat2_rad = radians(array[i].latitude);        var lng2_rad = radians(array[i].longitude);        // Use the "Spherical Law of Cosines" formula.        var dist = Math.acos(Math.sin(lat_rad) * Math.sin(lat2_rad) +                Math.cos(lat_rad) * Math.cos(lat2_rad) *                Math.cos(lng2_rad - lng_rad));        if (dist < closest_dist) {            closest = array[i];            closest_dist = dist;        }    }    return closest;};// Good : clear, easy to test spherical_distance in isolationvar spherical_distance = function (lat1, lng1, lat2, lng2) {    var lat1_rad = radians(lat1);    var lng1_rad = radians(lng1);    var lat2_rad = radians(lat2);    var lng2_rad = radians(lng2);    // Use the "Spherical Law of Cosines" formula.    return Math.acos(Math.sin(lat1_rad) * Math.sin(lat2_rad) +            Math.cos(lat1_rad) * Math.cos(lat2_rad) *            Math.cos(lng2_rad - lng1_rad));};var findClosestLocation = function (lat, lng, array) {    var closest;    var closest_dist = Number.MAX_VALUE;    for (var i = 0; i < array.length; i += 1) {        var dist = spherical_distance(lat, lng, array[i].latitude, array[i].longitude);        if (dist < closest_dist) {            closest = array[i];            closest_dist = dist;        }    }    return closest;};

 * 纯粹的Utility代码 (比如操作字符串,hash表,读写文件)
这类代码最好封装到一个独立的Util类或者函数,(ReadFileToString())

* 其他通用的代码

ajax_post({    url: ‘http://example.com/submit‘,    data: data,    on_success: function (response_data) {        var str = "{\n";        for (var key in response_data) {            str += " " + key + " = " + response_data[key] + "\n";        }        alert(str + "}");    });}// Continue handling ‘response_data‘ ...// Good : 函数名更容易定位,更容易维护var format_pretty = function (obj) {    var str = "{\n";    for (var key in obj) {        str += " " + key + " = " + obj[key] + "\n";    }    return str + "}";};// Better : 功能更强大var format_pretty = function (obj, indent) {    // Handle null, undefined, strings, and non-objects.    if (obj === null) return "null";    if (obj === undefined) return "undefined";    if (typeof obj === "string") return ‘"‘ + obj + ‘"‘;    if (typeof obj !== "object") return String(obj);    if (indent === undefined) indent = "";    // Handle (non-null) objects.    var str = "{\n";    for (var key in obj) {        str += indent + " " + key + " = ";        str += format_pretty(obj[key], indent + "                ") + "\n";    }    return str + indent + "}";};

 * 创造更多通用功能的代码
像之前的ReadFileToString(), format_pretty()都可以夸工程使用他们

* 工程特有的功能 (即使如此,依然可以考虑创建在工程内部使用的util类/函数)
* 简化现有的接口 (用到某个第三方的库,它的接口不好用,可以考虑对它封装一下)
  - Simplifying an existing interface
  - Reshaping an interface to your needs
  - Don‘t take things too far (不要将一个函数实现细分成太多的小函数,控制粒度)

一次只做一件事情(chap 11, one task at a time)
0. 一个代码片段只做一件事情 (空行风格的代码段)
示例1

// Bad : two things doing together (parseValue, computeScore)var vote_changed = function (old_vote, new_vote) {    var score = get_score();    if (new_vote !== old_vote) {        if (new_vote === ‘Up‘) {            score += (old_vote === ‘Down‘ ? 2 : 1);        } else if (new_vote === ‘Down‘) {            score -= (old_vote === ‘Up‘ ? 2 : 1);        } else if (new_vote === ‘‘) {            score += (old_vote === ‘Up‘ ? -1 : 1);        }    }    set_score(score);};// Good : clear to understandvar vote_value = http://www.mamicode.com/function (vote) {>

 示例2

// Bad : 不方便扩展var place = location_info["LocalityName"]; // e.g. "Santa Monica"if (!place) {    place = location_info["SubAdministrativeAreaName"]; // e.g. "Los Angeles"}if (!place) {    place = location_info["AdministrativeAreaName"]; // e.g. "California"}if (!place) {    place = "Middle-of-Nowhere";}if (location_info["CountryName"]) {    place += ", " + location_info["CountryName"]; // e.g. "USA"} else {    place += ", Planet Earth";}return place;// Goodvar town = location_info["LocalityName"]; // e.g.  "Santa Monica"var city = location_info["SubAdministrativeAreaName"]; // e.g.  "Los Angeles"var state = location_info["AdministrativeAreaName"]; // e.g.  "CA"var country = location_info["CountryName"]; // e.g.  "USA"// Start with the default, and keep overwriting with the most specific value.var second_half = "Planet Earth";if (country) {    second_half = country;}if (state && country === "USA") {    second_half = state;}var first_half = "Middle-of-Nowhere";if (state && country !== "USA") {    first_half = state;}if (city) {    first_half = city;}if (town) {    first_half = town;}return first_half + ", " + second_half;// Better : 利用js语法的a||b||c的特性var first_half, second_half;if (country === "USA") {    first_half = town || city || "Middle-of-Nowhere";    second_half = state || "USA";} else {    first_half = town || city || state || "Middle-of-Nowhere";    second_half = country || "Planet Earth";}return first_half + ", " + second_half;

 









读书笔记之《The Art of Readable Code》Part 3