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

'SOFTWARE ENGINEERING'에 해당되는 글 21건

  • 2017.09.18 개발자로써 와닿았던 명언들
  • 2017.09.12 Art of Readable code - Test-Friendly Development
  • 2017.08.09 TDD process from Test Driven Development
  • 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

개발자로써 와닿았던 명언들

SOFTWARE ENGINEERING 2017. 9. 18. 09:12

끊임없이 변하는 세상에서 가장 중요한 기술은 안목이다.

누구에게나 옳은 말은 아닐 것이다. 하지만 새로운 것을 알아보는 능력, 다른 이의 작업을 알아보는 능력 또는 어떤 일을 할 수 있는 여러 방법을 비교하고 당신, 팀, 프로젝트, 조직에 가장 적합한 것을 고를 수 있는 능력은 어마어마하게 소중하다. 내가 아는 이 대부분은 이에 능하지 못했고, 내가 아는 대부분의 리더는 이 부분에선 정말 엉망이었다.

누군가 당신에게 이걸 해야 한다고 말하는 일이나 블로그에서 읽은 것 또는 모두가 하는 걸 그대로 해내는 건 쉽다. 목적과 모든 면을 고려하여 살펴보고 자신에게 가장 잘 맞는 최적의 선택을 하는 게 훨씬 어렵다. 누구나 선택을 해야 하지만, 어떤 이들은 평가 자체를 두려워하여 아무거나 골라버리거나 남들이 하는 대로 따라가는 일도 흔하다.

목적을 달성하는 방법엔 여러 가지가 있지만, 고객 입장에선 뭐든 상관없다.

고객은 개발자가 겪는 문제가 뭔지 관심 없다. 그저 결과물인 소프트웨어가 자신이 원하는 작업을 해결해주길 바랄 뿐이다.

시스템에 문제가 생기고 예외가 발생하든 개발 장비에 문제가 생겼든 다른 개발자가 진상이거나 해커가 침입했든, 사용자에게는 별로 중요한 문제가 아니다. 문제가 생겼을 때 정직해지는 건 좋다. 그게 가끔이라면 말이다. 하지만 고객이 보기 전에 문제가 오래가지 않도록 해두는 편이 더 좋다.

목적을 달성하는 방법엔 여러 가지가 있지만, 고객 입장에선 뭐든 상관없다.

고객은 개발자가 겪는 문제가 뭔지 관심 없다. 그저 결과물인 소프트웨어가 자신이 원하는 작업을 해결해주길 바랄 뿐이다.

시스템에 문제가 생기고 예외가 발생하든 개발 장비에 문제가 생겼든 다른 개발자가 진상이거나 해커가 침입했든, 사용자에게는 별로 중요한 문제가 아니다. 문제가 생겼을 때 정직해지는 건 좋다. 그게 가끔이라면 말이다. 하지만 고객이 보기 전에 문제가 오래가지 않도록 해두는 편이 더 좋다.

로그를 남기지 않아 몰랐던 것이 큰 문제가 될 수 있다.

오늘날에도 소프트웨어가 어떻게 동작하는지 알기 위해 로그나 크래시 리포트, 사용 정보를 충분히 수집하지 않는 걸 보면서 놀라곤 한다. 이러한 정보를 수집하지 않는 사람들은 품질을 과신한다.

측정하고 기록하지 않으면 고객은 당연히 알게 될 문제를 개발자는 알 수 없다. 어떤 문제든 발생하는 즉시 알 수 있도록 나는 늘 세밀하고 유용한 로그, 크래시 추적, 리뷰와 코멘트 등 수집할 수 있는 건 모조리 해야 한다고 주장해왔다. 물론 아직도 이런 것들이 개발자가 되는데 전혀 필요 없다고 생각하는 사람들도 있지만 말이다.

툴을 쫓는 사람들

“기본을 정확히 세우라. 천천히 유익한 툴에 익숙해지고, 그것을 사용하며 지속적으로 효과적인 상태를 유지하라.”


신입 프론트엔드 개발자를 위한 면접 조언

 

포트폴리오

·         가능하면 GitHub이나 BitBucket 같은 Git 호스팅 서비스에 올려두자. 요즘은 SVN이든 Git이든 VCS를 사용하지 않는 업체를 찾기 어려울 정도다. 혹시 VCS를 전혀 사용하지 않는 개발 업체가 있다면 입사를 다시 한번 고민해보라고 진지하게 말하고 싶다. 입사 지원자에게 GitHub 계정 링크를 알려달라는 곳이 해외는 물론 국내에도 꽤 있다. 가능하면 포트폴리오를 앞서 말한 두 서비스 중 하나를 택해서 올려두는 게 좋다. 개인적으로는 GitHub을 추천하는데, 사용자가 더 많아서 문제가 생겼을 때 도움을 구하기 쉽기 때문이다.

·         .gitignore 파일에 .idea 폴더나 npm-debug.log 같은 불필요한 파일은 포함되지 않게 설정해두자. 코딩 능력과 상관없는 거지만 기본적인 사용법을 모르는 것처럼 보일 수 있다.

·         커밋 메시지는 의외로 많은 것을 말해준다. 신경 써서 좋은 커밋 메시지를 작성하는 게 좋다.

·         혹여 포트폴리오 소개서를 쓴다면 사용한 기술은 나열은 하되 강조하지는 않는 걸 추천한다. 신입에게는 대단한 기술 스택일지 몰라도 (아마) 면접관들에게는 그리 대단하지 않을 공산이 큰데, 그런 걸 강조하면 오히려 더 없어 보이기 때문. 반면 만에 하나라도 면접관의 관심을 끌 만한 기술이라면 굳이 강조하지 않아도 눈에 띌 것이다.

·         개인 프로젝트라 하더라도 테스트 케이스는 성의껏 작성해두자. 코딩 전에 하든 후에 하든, 어쨌든 작성해 두는 게 좋은 인상을 줄 수 있다.

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

파란실버라이트

To remember the time when I started learning Silver Light!

,

Art of Readable code - Test-Friendly Development

SOFTWARE ENGINEERING/TDD 2017. 9. 12. 10:44

TABLE 14-1. Characteristics of less testable code, and how this leads to problems with design



TABLE 14-2. Characteristics of more testable code, and how this leads to good design








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

파란실버라이트

To remember the time when I started learning Silver Light!

,

TDD process from Test Driven Development

SOFTWARE ENGINEERING/TDD 2017. 8. 9. 14:44




From Ebook : http://chimera.labs.oreilly.com/books/1234000000754/ch04.html#_recap_the_tdd_process

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

파란실버라이트

To remember the time when I started learning Silver Light!

,

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!

,
  • «
  • 1
  • 2
  • 3
  • »

카테고리

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

티스토리툴바