• 读书笔记之《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 isolation
    var 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 = "{
    ";
            for (var key in response_data) {
                str += " " + key + " = " + response_data[key] + "
    ";
            }
            alert(str + "}");
        });
    }
    // Continue handling 'response_data' ...
    
    // Good : 函数名更容易定位,更容易维护
    var format_pretty = function (obj) {
        var str = "{
    ";
        for (var key in obj) {
            str += " " + key + " = " + obj[key] + "
    ";
        }
        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 = "{
    ";
        for (var key in obj) {
            str += indent + " " + key + " = ";
            str += format_pretty(obj[key], indent + "
                    ") + "
    ";
        }
        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 understand
    var vote_value = function (vote) {
        if (vote === 'Up') {
            return +1;
        }
        if (vote === 'Down') {
            return -1;
        }
        return 0;
    };
    
    
    var vote_changed = function (old_vote, new_vote) {
        var score = get_score();
    
        score -= vote_value(old_vote); // remove the old vote
        score += vote_value(new_vote); // add the new vote
    
        set_score(score);
    };
    

     示例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;
    
    
    // Good
    
    var 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;
    









  • 相关阅读:
    Dynamics CRM 2015-超大Solution导入问题
    Dynamics CRM 2015-Data Encryption激活报错
    Dynamics CRM 2011-RootComponent Type
    Dynamics CRM 2015-Sign Out选项
    Dynamics CRM 2015-如何修改Optionset Default Value
    顶象直播实录:零售金融在线展业的风控实践(内含PPT)
    分析 | 央行二代征信有效防范多头借贷套利
    警示 | 天天都是315:防诈骗指南,速来领取↓↓↓
    “无接触”线上化转型加快 疫情下的物流大考
    “宅经济”,推动金融机构迎来新业务
  • 原文地址:https://www.cnblogs.com/xianzhon/p/6298336.html
Copyright © 2020-2023  润新知