SOFTWARE ENGINEERING/Art Of Readable Code

Ch7 Making Control Flow Easy to Read

파란실버라이트 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() 알려지지 않은 하위클래스의 코드를 호출할지도 모른다.