ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 5. 거대판 표현을 잘게 쪼개기
    Technique/Readable Code 2015. 12. 10. 12:39
    반응형

    코드의 표현이 커지면 커질수록 이해하기 더 어렵다


    ■ 거대한 표현을 더 소화하기 쉬운 여러 조각으로 나눈다


    설명변수

    - 작은 하위 포현을 담을 추가변수를 만드는것 

    - 추가변수 = 설명변수

    1
    2
    3
    4
    5
    6
    7
    8
    if(list.split(':')[0].strip() == "root"):
       ....
     
     
    username = line.split(':')[0].stript()
    if(username == "root"):
    ...
     
    cs


    위 코드와 같이 한번에 모든걸 다 하려고 하면 읽기 불편함이 많다.

    가장 기본적인 방법중 하나이다


    요약변수

    - 의미를 쉽게 파악할수 있어 별도의 설명을 요구하지 않는 표현이라고 해도 새로운 변수로 담아두는 방법은 유용할 수 있다.

    - 코다란 코드의 덩어리를 짧은 이름으로 대체하여 더 쉽게 관리하고 파악하는 목적을 가진 변수


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    if( request.user.id == document.owner_id ){
        ...
     
    if( request.user.id != document.owner_id ){
        ...
    }  
     
    final boolean user_owns_document = (request.user_id == document.owner_id); 
     
    if( user_owns_document ){    
    ...
    }
     
    if!user_owns_document ){
        ...
    }
    cs


    위와 같이 1~8번 라인 보다

    10~18번 라인의 구성이 더 읽기 편하다는 것!

    10번라인을 보는 사람은 하위 코드를 읽기전에 이녀석이 뭔가 이 함수에서 중요한 역활을 하겟구나.. 라고 생각 할 것이다.


    드모르간의 법칙 사용하기

    - not을 분배하고 and/or를 바꿔라

    혹은 거꾸로 not을 빼내기도 한다


    1
    2
    3
    4
    5
    6
    not(a or b or c) <=> (not a) and (not b) and (not c)
    not(a and b and c) <=> (not a) or (not b) or (not c) 
     
    if!(file_exists && !is_protected) ) Error("msg");
    if!file_exists || is_protected ) Error("msg");
     
    cs


    어떻게 불리언을 분류하느냐도 상당히 중요한 것 같다.


    쇼토 서킷 논리 오용 말기

    - 대부분의 프로그래밍 언어에서 불리언 연산은 쇼토 서킷 평가를 수행한다.

    1
    if( a || b )
    cs

    이코드는 a가 참일 경우 b는 평가하지 않는다.

    - 이는 매우 편리하지만 때로는 복잡한 연산을 수행할 때 오용될 수 도 있다.

    1
    2
    3
    4
    assert( ( !(bucket = FindBucket(key) ) ) || !bucket->IsOccupied() ); 
     
    bucket = FindBucket(key);
    if( bucket != NULL ) assert( !bucket->IsOccupied() );
    cs

    1번 과 같은 코드를 만나면 왠만한 코드는 키보드에서 손을때고 코드를 바라보면서 이해할 시간이 필요 할 것이다.

    하지만 후자와 같은 경우엔 코드가 2줄로 늘어 낫지만 이해하기는 더욱더 쉽다.

    왜 1줄짜리 거대한 표현으로 작성 되었을까?

    - 코드를 작성하던 당시에는 그렇게 하는 게 매우 영리하다고 생각했기 떄 문

    - 짧은 코드에 논리를 집어넣는 행위에는 어떤 즐거움이 있기 때문

    - 문제는 바로 그런 코드가 나중에 코드를 읽는 사람에게는 정신적은 장애물이 된다는데 있다!

    ■ 영리하게 작성된 코드에 유의하라 나중에 다른 사람이 읽은면 그런 코드가 종종 혼란을 초래한다


    거대한 구문 나누기

    1
    2
    3
    4
    5
    6
    7
    8
    9
    var update_hightlit = function ( message_num ){
        if( $("$vote_value" + message_num).html() === "up" ){
             ...    
        }else if( $("$vote_value" + message_num).html() === "down" ){
            ...    
        }else {
            ...    
        }
    }
    cs


    위 코드에 있는 개별적인 표현은 그렇게 크지 않지만, 모두 한 곳에 있어서 코드를 읽는 사람의 머리를 강타하는 거대한 구문을 형성한다
    다행히도 표현하는 부분이 동일하다 따라서 동일한 부분을 요약변수로 추출해서 함수의 앞부분에 모아 둘 수 있다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    var update_hightlight = 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 = "class name";
     
        if ( vote_value === "up" ){
             ...    
        }else if ( vote_value === "down" ){
            ...
        }else{
            ...
        }
    };
    cs


    반드시 위처럼 표현할 필요는 없지만 이렇게 표기를 한다면 

    - 타이핑 실수를 피할 수있다.

    - 코드를 하눈에 훑어보는데 용이하도록 코드의 길이를 조금이라도 더 줄여준다.

    - 클래스명을 변경해야 할 때 한 곳만 바꾸면 된다. 

    위 코드의 ... 부분은 선택된 섬네일에 클래스를 추가해주는 함수이다. 그리고 거대한 코드는 이 작업을 하나의 if마다 따로따로 해주고 있기에

    클래스명에 오타가 날 가능성이 크다는 이야기이다.


    표현을 단순화하는 다른 창의적인 방법들

    c++의 예제 코드를 보자

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    void addStars( 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_from.free_memory() );
        add_to->set_swap_memory( add_from.swap_memory() + add_from.swap_memory() );
        add_to->set_status_string( add_from.status_string() + add_from.status_string() );
        add_to->set_num_process( add_from.num_process() + add_from.num_process() );
         ...
    }
     
    void AddStats( const Stats& add_from, Stats* add_to ){    
        #define ADD_FIELD(field) add_to->set_##field( add_from.filed() + add_to->field() )
     
        ADD_FIELD( total_memory );
        ADD_FIELD( free_memory );
        ADD_FIELD( swap_memory );
        ADD_FIELD( status_string );
        ADD_FIELD( num_process );
    }
    cs


    1~8번 라인의 코드는 10초? 20초? 가까이 지켜보면 정말 간단한 걸 한다는게 알게 될 것이다.

    하지만  c++에서는 메크로 기능을 이용하여 아래와 같이 수정할 수 있다.

    눈을 어지럽히는 내용을 모두 제거했으므로 코드를 다시 일그면 핵심을 즉시 이해할 수 있다.

    매크로 사용을 권장하는 게 아니지만 위 처럼 가독성을 높이는 방법으로 도움을 주기도 한다.


    이 방법은 어디까지나 가독성에 도움을 준다와, 다른 프로그래머가 코드를 좀더 쉽게 이해하는데 도움을 준다 라는 것에 대한 이야기이다.

    반드시 이렇게 할 필요도없고, 자신이 어느정도 필요한다고 느끼는 것을 이용한다면 좋겠다.

    난 상당히 도움이 되는 것 같다. 코드 짤때 좀더 생각 해야 할 것 같다. ㅎㅎ

    반응형

    'Technique > Readable Code' 카테고리의 다른 글

    7.상관없는 하위 문제 추출  (0) 2015.12.11
    6. 변수와 가독성  (0) 2015.12.10
    4. 흐름제어  (0) 2015.12.10
    3. 주석  (0) 2015.12.09
    2. 미학 - 읽기 편한 코드 작성  (0) 2015.12.09

    댓글

Designed by Tistory.