#PARAN SILVERLIGHT#
  • Tistory
    • 관리자
    • 글쓰기
Carousel 01
Carousel 02
Previous Next

'SOFTWARE ENGINEERING/Art Of Readable Code'에 해당되는 글 12건

  • 2012.11.23 Ch14 Testing and Readability
  • 2012.11.23 Ch12 Turning Thoughts into Code
  • 2012.11.23 Ch11 OneTask At A Time
  • 2012.11.23 Ch10 Extracting Unrlated Subproblems
  • 2012.11.23 Ch9 Variables and Readability
  • 2012.11.23 Ch8 Breaking Down Giant Expressions
  • 2012.11.23 Ch7 Making Control Flow Easy to Read
  • 2012.11.23 Ch6 Making Comments Precise and Compact
  • 2012.11.23 Ch5 Knowing What to Comment 1
  • 2012.11.23 Ch4 Aesthetics

Ch14 Testing and Readability

SOFTWARE ENGINEERING/Art Of Readable Code 2012. 11. 23. 13:03

1. Make Tests Easy to Read and Maintain

 

function Test1() {
    vector<ScoredDocument> docs;
    docs.resize(5);
    docs[0].url = "http://example.com";
    docs[0].score = -5.0;
    docs[1].url = "http://example.com";
    docs[1].score = 1;

    docs[2].url = "http://example.com";
    docs[2].score = 4;
    docs[3].url = "http://example.com";
    docs[3].score = -99998.7;
    docs[4].url = "http://example.com";
    docs[4].score = 3.0;
    SortAndFilterDocs(docs);
    assert(docs.size() == 3);
    assert(docs[0].score == 4);
    assert(docs[1].score == 3.0);
    assert(docs[2].score == 1);

/*    There are at least eight different problems with this test code. By the end of the chapter, you’ll
    be able to identify and fix all of them.*/
}


//As a first step in cleaning this up, we could create a helper function like:
function MakeScoredDoc( ScoredDocument ,  score,  url) {
    ScoredDocument.score = score;
    ScoredDocument.url = url;
}

//Using this function, our test code becomes slightly more compact:
    void function() {
    vector<ScoredDocument> docs;
    docs.resize(5);
    MakeScoredDoc(docs[0], -5.0, "http://example.com");
    MakeScoredDoc(docs[1], 1, "http://example.com");
    MakeScoredDoc(docs[2], 4, "http://example.com");
    MakeScoredDoc(docs[3], -99998.7, "http://example.com");
    //...
}


void MakeScoredDoc( docs,  score) {
    var ScoredDocument ;
    ScoredDocument.score = score;
    ScoredDocument.url = "http://example.com";
    docs.push_back(sd);
}
//Using this function, our test code is even more compact:
function Test1() {
    vector<ScoredDocument> docs;
    AddScoredDoc(docs, -5.0);
    AddScoredDoc(docs, 1);
    AddScoredDoc(docs, 4);
    AddScoredDoc(docs, -99998.7);
    //...
}


 이 테스트는 어떤 점이 잘못되었을까?


 // 'Doc'를 내림차순으로 정렬하고 점수가 0보다 작은 문서를 제거한다.

 void SortAndFilterDocs(vector<ScoredDocument>* docs);


Void Tes1()

{

vector<ScoreDocument> docs;

docs.resize(50;

doc[0].url= "http://example.com":

doc[0].score = -5.0;

doc[1].url= "http://example.com":

doc[1].score = 1;

doc[2].url= "http://example.com":

doc[2].score = 4;

doc[3].url= "http://example.com":

doc[3].score = -99998.7;

doc[4].url= "http://example.com":

doc[4].score = 3;


SortAndFilterDocs(&docs);


assert(doc.size() == 3);

assert(docs[0].score = 4);

assert(docs[1].score = 3.0);

assert(docs[2].score = 1);


}



1. 덜 중요한 세부사항은 사용자가 볼 필요 없게 숨겨서 더 중요한 내용이 눈에 잘 띄게 해야한다.


 => Helper function을 작성

 void MakeScoredDoc(ScoredDocument* sd, double score, string url)

{

sd->score = score;

sd-> url = url 

}


void Test1()

{

vector<ScoreDocument> docs;

docs.resize(5);

MakeStoredDoc(&doc[0], -5.0 "http://exmaple.com");

MakeStoredDoc(&doc[1], 1 "http://exmaple.com");

MakeStoredDoc(&doc[2], 4 "http://exmaple.com");

MakeStoredDoc(&doc[3], -99998.7 "http://exmaple.com");

....

}


2. 아직 세부내용이 보인다. 예를 들어 "http://example.com"

=> Helper 함수가 더 많은 일을 하게 만들고 이름 addScoredDoc()

 void AddScoredDoc(vector<ScoredDocument>& docs, double score) 

{

ScoreDocument sd;

sd.score = score;

sd.url = "http://example.com";

docs.push_back(sd);

}


void Test1()

{

vector<ScoredDocument> docs;

AddScoredDoc(docs, -5.0);

AddScoredDoc(docs, 1);

AddScoredDoc(docs, 4);

AddScoredDoc(docs, -99998.7);

....

}


3. 최소한의 테스트 구문 만들기 

 - 생각을 코드로 만들기를 적용해서 쉬운 말로 작성해보자. 

 [5,1,4,-99998.7, 3] 과 같은 점스를 가지는 문서 리스트가 있다. 

 SortAndFilterDocs()를 호출한 다음에 문서는 ][4,3,1]이라는 순서대로 가져야 한다. 

 => vector<ScoreDocument.에 대한 언급이 없다. 점수를 담는 배영 자체는 중요하지 않다.


 - 이상적인 테스트 코드

 CheckScoresBeforeAfter("-5,1,4, -99998.7, 3 " , "4,3,1");


4. 목적에 맞는 '미니-랭귀지' 구현하기

 void CheckScoresBeforAfter(string input, string expected_output)

{

vector<Scoreddocument> docs = ScoredDocsFromString(input);

SortAndfilterDocs(&docs);

string output = ScoredDocsToString(docs);

assert(output == expected_output) ;

}


아래 helper 함수를 작성해야 한다. 

vector<Scoreddocument>ScoredDocsFromString(string scores)

{

....

}


string ScoredDocsToString(vector<ScoredDocument> docs) 

{

...

}


이제 전체 테스트를 단 한 번의 CheckScoresBeforAfter() 호출로 작성할 수 있다. 

책에서는 분량이 많지만 기능이 강력하다고 하는데.. 이렇게 많이 적어야 하나. 테스트 코드를.ㅠㅠ


5. 읽기 편한 메시지 만들기

 What if ,  assert(output == expected_output) 가 실패한다면 ?

 Assertion failed: (output == expected_output) , 

function CheckScoreBeforeAfter, file text.cc, line 37 메시지가 뜬다면 expected_output 값이 무엇인지 궁금할 것이다.

 부스트 C++ 라이브러이리에 포함된 BOOST_REQUIRE_EQUAL(output, expected_output) 함수를 쓰면 

      output == expected_output failed ["1,3,4 != 4,3,1"] 과 같은 메시지를 볼수 있을 것이다. 

 => XUnit 처럼 도움이 되는 라이브러리 혹은 프레임워크가 있을 것이다  찾아서 사용하자. 


6. 아니면 CheckScoreBeforeAfter() 에 실패할 경우 message를 보여줄 수 있도록 코드를 추가하자.

 => 핵심은 에러메시지가 최대한 유용해야한다. 

  void CheckScoresBeforeAfter(...) 

{

 ...

if (output != expected_output) {

cerr << "CheckScoresBeforeAfter() failed, " << 

cerr << "input :" << 

cerr << "expected output : " << 

cerr << "Actual Output" << 

abort();

}


7. 좋은 테스트 값을 선택 

 CheckScoresBeforeAfter("2, 1, 3 " , "3, 2, 1"); // 기본적인 정렬

 CheckScoresBeforeAfter("0 , -0.1, -10 " , "0"); // 0보다 작은 값을 모두 제거

 CheckScoresBeforeAfter("1, -2, 1, -2" , "1, 1"); // 중복은 문제되지 않는다.

 CheckScoresBeforeAfter("" , ""); // 빈 입력도 OK


8. Test 함수에 이름 붙이기.


void Test1()

{ }

=> void Test_SortAndFilterDocs()

{

} 



 테스트에 친숙한 개발 


저작자표시 비영리 (새창열림)
블로그 이미지

파란실버라이트

To remember the time when I started learning Silver Light!

,

Ch12 Turning Thoughts into Code

SOFTWARE ENGINEERING/Art Of Readable Code 2012. 11. 23. 13:01

1.Describing Logic Clearly

 

$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 ...

 

//Here is an alternative solution inspired by this description:

    if (is_admin_request()) {
// authorized
    } elseif ($document && ($document['username'] == $_SESSION['username'])) {
// authorized
} else {
    return not_authorized();
}

// continue rendering the page ...

저작자표시 비영리 (새창열림)
블로그 이미지

파란실버라이트

To remember the time when I started learning Silver Light!

,

Ch11 OneTask At A Time

SOFTWARE ENGINEERING/Art Of Readable Code 2012. 11. 23. 11:45

1.Extracting Values from an Object

 

var old = function () {

 

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

 

//we rewrote the original code to solve each of these tasks independently.

 

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 RefactoredCode = function () {

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


var RefactoredCode2 = function () {

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

 

2. Tasks Can Be Small

/*
When the user clicks one of the buttons (to make/change her vote), the following JavaScript
is called:
    vote_changed(old_vote, new_vote); // each vote is "Up", "Down", or ""
This function updates the total score and works for all combinations of old_vote/new_vote:*/

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

 

/*
We can make the code easier to read by solving each task separately. The following code solves
the first task, of parsing the vote into a numerical value:*/

var vote_value = function (vote) {
    if (vote === 'Up') {
        if (vote === 'Down') {
            return -1;
        }
        return 0;
    }
}

//Now the rest of the code can solve the second task, updating score:
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);
}
/*As you can see, this version of the code takes a lot less mental effort to convince yourself that
it works. That’s a big part of what makes code “easy to understand.”*/

 

저작자표시 비영리 (새창열림)
블로그 이미지

파란실버라이트

To remember the time when I started learning Silver Light!

,

Ch10 Extracting Unrlated Subproblems

SOFTWARE ENGINEERING/Art Of Readable Code 2012. 11. 23. 11:41

1. find Closest Location

 

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

 

/*
Most of the code inside the loop is working on an unrelated subproblem: Compute the spherical
distance between two lat/long points. Because there is so much of that code, it makes sense to
extract it into a separate spherical_distance() function:
*/

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

 

2.Other General-Purpose Code

 

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

 

/*The high-level goal of this code is, Make an Ajax call to the server, and handle the response. But a
lot of the code is solving the unrelated subproblem, Pretty-print a dictionary. It’s easy to extract
that code into a function like format_pretty(obj):*/

var format_pretty = function (obj) {
    var str = "{\n";
    for (var key in obj) {
        str += " " + key + " = " + obj[key] + "\n";
    }
    return str + "}";
};

 

//adding this functionality is easy. Here’s what the improved code looks like:

var format_pretty_1 = 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
}

 

 

 

저작자표시 비영리 (새창열림)
블로그 이미지

파란실버라이트

To remember the time when I started learning Silver Light!

,

Ch9 Variables and Readability

SOFTWARE ENGINEERING/Art Of Readable Code 2012. 11. 23. 11:36

 

1.Eliminating Intermediate Results


//Here’s an example of a JavaScript function that removes a value from an array:
    var remove_one = function (array, value_to_remove) {
        var index_to_remove = null;
        for (var i = 0; i < array.length; i += 1) {
            if (array[i] === value_to_remove) {
                index_to_remove = i;
                break;
            }
        }
        if (index_to_remove !== null) {
            array.splice(index_to_remove, 1);
        }
    };

 

//sometimes be eliminated by handling the result as soon as you get it:
    var remove_one = function (array, value_to_remove) {
        for (var i = 0; i < array.length; i += 1) {
            if (array[i] === value_to_remove) {
                array.splice(i, 1);
                return;
            }
        }
    };

 

2. if Statement Scope in C++

 

//the person reading this
//code might keep info in mind, wondering if/how it will be used again.
PaymentInfo* info = database.ReadPaymentInfo();
if (info) {
    cout << "User paid: " << info->amount() << endl;
}
// Many more lines of code below ...


//Now the reader can easily forget about info after it goes out of scope.
if (PaymentInfo* info = database.ReadPaymentInfo()) {
    cout << "User paid: " << info->amount() << endl;
}

 

3. Shrink the Scope of Your Variables

 

//two methods, in the following way:
    class LargeClass {

    string str_;

    void Method1() {
        str_ = ...;
        Method2();
    }
    void Method2() {
// Uses str_
    }
// Lots of other methods that don't use str_ ...
};


//For this case, it may make sense to “demote” str_ to be a local variable:
    class LargeClass {
    void Method1() {
        string str = ...;
        Method2(str);
    }

    void Method2(string str) {
// Uses str
    }
// Now other methods can't see str.
};

 

 

 

 

 

 

 

 

 

 

 

저작자표시 비영리 (새창열림)
블로그 이미지

파란실버라이트

To remember the time when I started learning Silver Light!

,

Ch8 Breaking Down Giant Expressions

SOFTWARE ENGINEERING/Art Of Readable Code 2012. 11. 23. 11:30

1. Another Creative Way to Simplify Expressions

 

void AddStats(const Stats& add_from, Stats* add_to) {


 add_to->set_total_memory(add_from.total_memory() + add_to->total_memory());
 add_to->set_free_memory(add_from.free_memory() + add_to->free_memory());
 add_to->set_swap_memory(add_from.swap_memory() + add_to->swap_memory());
 add_to->set_status_string(add_from.status_string() + add_to->status_string());
 add_to->set_num_processes(add_from.num_processes() + add_to->num_processes());
 ...

 

 }

 

 After ten seconds of careful scrutiny, you might realize that each line is doing the same thing,
 just to a different field each time:

 

 add_to->set_XXX(add_from.XXX() + add_to->XXX())

 

 In C++, we can define a macro to implement this:

 

 void AddStats(const Stats& add_from, Stats* add_to) {
 #define ADD_FIELD(field) add_to->set_##field(add_from.field() + add_to->field())
 ADD_FIELD(total_memory);
 ADD_FIELD(free_memory);
 ADD_FIELD(swap_memory);
 ADD_FIELD(status_string);
 ADD_FIELD(num_processes);
 ...
 #undef ADD_FIELD
 }

 

2. Breaking Down Giant Statements

 

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

 

//his is also an instance of the DRY—Don’t Repeat Yourself—principle):


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

 

3. Explaining Variables

 

Here is an example:
    if line.split(':')[0].strip() == "root":
...
Here is the same code, now with an explaining variable:
    username = line.split(':')[0].strip()
    if username == "root":

 

4. Summary Variables

 

var CleanReply = function (request,  reply)
{
    //For example, consider the expressions in this code:
    if (request.user.id == document.owner_id) {
        // user can edit this document...
    }

    if (request.user.id != document.owner_id) {
        // document is read-only...
    }

    //stated more clearly by adding a summary variable:
    var user_owns_document = (request.user.id == document.owner_id);

 

    if (user_owns_document) {
        // user can edit this document...
    }

    if (!user_owns_document) {
        // document is read-only...
    }

}

 

5.Using De Morgan’s Laws (positive is easy to readable)

 

var Contains = function (request,  reply)
{
/*    1) not (a or b or c) ⇔ (not a) and (not b) and (not c)
    2) not (a and b and c) ⇔ (not a) or (not b) or (not c)*/


    //You can sometimes use these laws to make a boolean expression more readable. For instance,
    //if your code is:
    if (!(file_exists && !is_protected)) Error("Sorry, could not read file.");

    //It can be rewritten to:
    if (!file_exists || is_protected) Error("Sorry, could not read file.");
}

 


 

 

저작자표시 비영리 (새창열림)
블로그 이미지

파란실버라이트

To remember the time when I started learning Silver Light!

,

Ch7 Making Control Flow Easy to Read

SOFTWARE ENGINEERING/Art Of Readable Code 2012. 11. 23. 11:21

1.Conditional Expression

 

var CleanReply = function (request,  reply)
{
    //Here’s a case where the ternary operator is readable and compact:

    time_str += (hour >= 12) ? "pm" : "am";

 

    //Avoiding the ternary operator, you might write:
    if (hour >= 12) {
        time_str += "pm";
    } else {
        time_str += "am";
    }


    //these expressions can quickly become difficult to read:
    exponent >= 0 ? mantissa * (1 << exponent) : mantissa / (1 << -exponent);

 

    //Spelling out the logic with an if/else statement makes the code more natural:

    if (exponent >= 0) {
        return mantissa * (1 << exponent);
    } else {
        return mantissa / (1 << -exponent);
    }

}

 

2.don’t” is drowned out by the more unusual

 

var CleanReply = function (request,  reply)
{
    if (!url.HasQueryParameter("expand_all")) {
        response.Render(items);
    } else {
        for (var i = 0; i < items.size(); i++) {
            items[i].Expand();
        }

    }


/*    it’s the more interesting case (and it’s the
    positive case, too), let’s deal with it first:*/
    if (url.HasQueryParameter("expand_all")) {
        for (var i = 0; i < items.size(); i++) {
            items[i].Expand();
        }

    }else {
        response.Render(items);
    }
}

 

3.Removing Nesting Inside Loops

 

var Contains = function (request,  reply)
{
/*    here’s a case of code
    nested in a loop:*/
    for (var i = 0; i < results.size(); i++) {
        if (results[i] != NULL) {
            //non_null_count++
            if (results[i].name != "") {
                //cout << "Considering candidate..." << endl;

            }

        }
    }

 

    //Inside a loop, the analogous technique to returning early is to continue:
    for (int i = 0; i < results.size(); i++) {
        if (results[i] == NULL) continue

            //non_null_count++;
        if (results[i].name == "") continue;
            //cout << "Considering candidate..." << endl;

    }

}

 

4. Removing Nesting by Returning Early

 

var CleanReply = function (request,  reply)
{
    //if you notice yourself looking back up to doublecheck
    //which block conditions you’re in:
    if (user_result == SUCCESS) {
        if (permission_result != SUCCESS) {
            reply.WriteErrors("error reading permissions");
            reply.Done();
            return;
        }
        reply.WriteErrors("");
    } else {
        reply.WriteErrors(user_result);
    }
    reply.Done();

    //Nesting like this can be removed by handling the “failure cases”
    //as soon as possible and returning early from the function:

    if (user_result != SUCCESS) {
        reply.WriteErrors(user_result);
        reply.Done();
        return;
    }
    if (permission_result != SUCCESS) {
        reply.WriteErrors(permission_result);
        reply.Done();
        return;
    }
    reply.WriteErrors("");
    reply.Done();

}

 

5. Returning Early from a Function

//Returning early from a function is perfectly fine—and often desirable. For example:

var Contains = function (request,  reply)
{
    if (str == null || substr == null) return false;
    if (substr.equals("")) return true;

}


cf) 반환 포인트를 하나만 두려는 건 함수의 끝부분에서 실행되는 cleanup 코드의 호출을 보장하려는 의도다. 

    하지만 현대의 언어는 클린업 코드를 실행시키는 더 정교한 방법을 제공한다. C# 의 Using / try finally

    그러므로 여러 곳에서 반환하는 것도 바람직 할 수 있다.

 

 6. 아래와 같은 구조가 차지하는 것이 많은 프로그램은 흐름을 쫒아가기 어려워질 수 있다. 이 비율이 너무 놓지 않아야한다.

  쓰레딩                        - 어느 코드가 언제 실행되는지 불분명

  시그널/ 인터럽트 핸들러 - 어느 코드가 어떤 시점에 실행될지 모른다.

  예외                           - 예외 처리가 여러 함수 호출을 거치면서 실행될 수 있다.

  함수 포인터 & 익명함수  - 실행할 함수가 런타임에 결정되기 때문에 컴파일 과정에서는 어떤코드가 실행될지 알기 어렵다.

  가상 메소드                  - object.virtualmethod() 알려지지 않은 하위클래스의 코드를 호출할지도 모른다.  

저작자표시 비영리 (새창열림)
블로그 이미지

파란실버라이트

To remember the time when I started learning Silver Light!

,

Ch6 Making Comments Precise and Compact

SOFTWARE ENGINEERING/Art Of Readable Code 2012. 11. 23. 11:13

1.Describe Function Behavior Precisely

 

// Return the number of lines in this file.
var CountLines = function (filename,  reply)
{
    //# remove everything after the second '*'
    name = '*'.join(line.split('*')[2]);

}

// Count how many newline bytes ('\n') are in the file.
var CountLines = function (filename,  reply)
{
    //# remove everything after the second '*'
    name = '*'.join(line.split('*')[2]);

}

// Rearrange 'v' so that elements < pivot come before those >= pivot;
// Then return the largest 'i' for which v[i] < pivot (or -1 if none are < pivot)
var Partition = function (filename,  reply)
{
    //# remove everything after the second '*'
    name = '*'.join(line.split('*')[2]);

}

// Example: Partition([8 5 9 8 2], 8) might result in [5 2 | 8 9 8] and return 1
var Partition = function (filename,  reply)
{
    //# remove everything after the second '*'
    name = '*'.join(line.split('*')[2]);

}


 

저작자표시 비영리 (새창열림)
블로그 이미지

파란실버라이트

To remember the time when I started learning Silver Light!

,

Ch5 Knowing What to Comment

SOFTWARE ENGINEERING/Art Of Readable Code 2012. 11. 23. 11:07

1.Comment the Flaws in Your Code


// Enforce limits on the Reply as stated in the Request,
// such as the number of items returned, or total byte size, etc.
var CleanReply = function (request,  reply)
{
/*    Marker Typical meaning
    TODO: Stuff I haven’t gotten around to yet
    FIXME: Known-broken code here
    HACK: Admittedly inelegant solution to a problem
    XXX: Danger! major problem here*/

}


TODO : 아직 하지 않은 일

FIXME:  오동작을 일으킨다고 알려진 코드

HAXK : 아름답지 않은 해결책

XXX: 위험! 여기 큰 문제가 있다.

TextMate : ESC

 

2.Comment on Your Constants

 

/// Make sure 'reply' meets the count/byte/etc. limits from the 'request'
var EnforceLimitsFromRequest = function (request,  reply)
{
    NUM_THREADS = 8     ;

    NUM_THREADS = 8 // as long as it's >= 2 * num_processors, that's good enough.

    // Impose a reasonable limit - no human can read that much anyway.
    var  MAX_RSS_SUBSCRIPTIONS = 1000;

    var image_quality = 0.72; // users thought 0.72 gave the best size/quality tradeoff

}

 

3.Don’t Comment Bad Names—Fix the Names Instead

 

void CleanReply(Request request, Reply reply); // comment for a function named CleanReply():

void EnforceLimitsFromRequest(Request request, Reply reply);
/*This function name is more “self-documenting.” A good name is better than a good comment
because it will be seen everywhere the function is used.
    

void DeleteRegistry(RegistryKey* key);

void ReleaseRegistryHandle(RegistryKey* key);

/*The name DeleteRegistry() sounds like a dangerous function (it deletes the registry?!). The
comment “This doesn’t modify the actual registry” is trying to clear up the confusion.
    Instead, we could use a more self-documenting name like:*/

 

4.Put Yourself in the Reader’s Shoes
*struct Recorder {
    vector<float> data;
...
    void Clear() {
        vector<float>().swap(data); // Huh? Why not just data.clear()?
    }
};

//it turns out that this is the only way to force a vector to
//truly relinquish its memory to the memory allocator


void Clear() {

    // Force vector to relinquish its memory (look up "STL swap trick")
    vector<float>().swap(data);
}
*};


저작자표시 비영리 (새창열림)
블로그 이미지

파란실버라이트

To remember the time when I started learning Silver Light!

,

Ch4 Aesthetics

SOFTWARE ENGINEERING/Art Of Readable Code 2012. 11. 23. 10:52

1. Break Code into Paragraphs

 

var euclidean_norm = function (v)
{

/*# Import the user's email contacts, and match them to users in our system.
# Then display a list of those users that he/she isn't already friends with.*/

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


var euclidean_norm = function (v)
{

    //# 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)
}

 

2. Organize Declarations into Blocks

 

class 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();
    // Handlers
    void ViewProfile(HttpRequest* request);
    void SaveProfile(HttpRequest* request);
    void FindFriends(HttpRequest* request);
    // Request/Reply Utilities
    string ExtractQueryParam(HttpRequest* request, string param);
    void ReplyOK(HttpRequest* request, string html);
    void ReplyNotFound(HttpRequest* request, string error);
    // Database Helpers
    void OpenDatabase(string location, string user);
    void CloseDatabase(string location);
};

 

3.Rearrange Line Breaks to Be Consistent and Compact

public class PerformanceTester {
    public static final TcpConnectionSimulator wifi = new TcpConnectionSimulator(
        500, /* Kbps */
        80, /* millisecs latency */
        200, /* jitter */
        1 /* packet loss % */);
    public static final TcpConnectionSimulator t3_fiber =  new TcpConnectionSimulator(
            45000, /* Kbps */
            10, /* millisecs latency */
            0, /* jitter */
            0 /* packet loss % */);
    public static final TcpConnectionSimulator cell = new TcpConnectionSimulator(
        100, /* Kbps */
        400, /* millisecs latency */
        250, /* jitter */
        5 /* packet loss % */);
}

 

public class PerformanceTester {
    public static final TcpConnectionSimulator wifi =
        new TcpConnectionSimulator(
            500,    /* Kbps */
            80,     /* millisecs latency */
            200,    /* jitter */
            1       /* packet loss % */);
    public static final TcpConnectionSimulator t3_fiber =
        new TcpConnectionSimulator(
            45000,  /* Kbps */
            10,     /* millisecs latency */
            0,      /* jitter */
            0       /* packet loss % */);
    public static final TcpConnectionSimulator cell =
        new TcpConnectionSimulator(
            100,    /* Kbps */
            400,    /* millisecs latency */
            250,    /* jitter */
            5       /* packet loss % */);
}

 

public class PerformanceTester {
// TcpConnectionSimulator(throughput, latency, jitter, packet_loss)
                        // [Kbps] [ms] [ms] [percent]

    public static final TcpConnectionSimulator wifi =
        new TcpConnectionSimulator(500, 80, 200, 1);
    public static final TcpConnectionSimulator t3_fiber =
        new TcpConnectionSimulator(45000, 10, 0, 0);
    public static final TcpConnectionSimulator cell =
        new TcpConnectionSimulator(100, 400, 250, 5);
}

 

 

저작자표시 비영리 (새창열림)
블로그 이미지

파란실버라이트

To remember the time when I started learning Silver Light!

,
  • «
  • 1
  • 2
  • »

카테고리

  • Inforamtion Technology (281)
    • DESIGN PATTERN (33)
      • 실용주의 디자인패턴 (29)
    • SOFTWARE ENGINEERING (21)
      • Art Of Readable Code (12)
      • Object Oriented Programming (6)
      • TDD (2)
    • FRAMEWORK (22)
      • Spring.net (2)
      • LightSwitch (20)
    • PROGRAMING (58)
      • C# (20)
      • .NET (6)
      • HTML5 (7)
      • ASP.NET (9)
      • SILVERLIGHT (7)
      • Ruby On Rails (6)
    • PROJECT MANAGEMENT (10)
      • SW Version Management (7)
      • Schedulring Management (1)
    • BOOKS (18)
    • MOBILE APP (1)
      • SENCHA TOUCH (1)
    • SECURITY (5)
    • MES (1)
    • B2B (14)
      • WEBMETHODS (4)
    • ERP (53)
      • SAP/R/3 (51)
    • ABOUT TOOLS (2)
    • FUNDAMENT CONCEPT (21)
    • SOA BPM (22)
    • PORTFOLIO (0)

태그목록

  • 프로그래밍
  • 병렬
  • 동시성

최근에 받은 트랙백

글 보관함

링크

파란실버라이트

블로그 이미지

To remember the time when I started learning Silver Light!

LATEST FROM OUR BLOG

RSS 구독하기

LATEST COMMENTS

BLOG VISITORS

  • Total :
  • Today :
  • Yesterday :

Copyright © 2015 Socialdev. All Rights Reserved.

티스토리툴바