2020. 11. 3. 20:52

컴파일러나 인터프리터만 통과하려는 생각으로 코드를 구현하는 프로그래머는 스스로 문제를 일으킨다


예를 들어, 동일한 범위 안에서는 다른 두 개념에 같은 이름을 사용하지 못한다


그래서 프로그래머가 한쪽 이름을 마음대로 바꾸고픈 유혹에 빠진다


어떤 프로그래머는 철자를 살짝 바꿨다가 나중에 철자 오류를 고치는 순간 컴파일이 불가능한 상황에 빠진다


컴파일러를 통과할지라도 연속된 숫자를 덧붙이거나 불용어를 추가하는 방식은 적절하지 못하다


이름이 달라져야 한다면 의미도 달라져야 한다


연속적인 숫자를 덧붙인 이름(a1, a2, ..., aN)은 의도적인 이름과 정반대다


이런 이름은 그릇된 정보를 제공하는 이름도 아니며, 아무런 정보를 제공하지 못하는 이름일 뿐이다



public static void copyChars(char a1[], char a2[]) {

    for(int i = 0; i < a1.length; ++i)

        a1[i] = a2[i];

    }

}


함수 인수 이름으로 source와 destination을 사용한다면 코드 읽기가 훨씬 더 쉬워진다



불용어를 추가한 이름 역시 아무런 정보도 제공하지 못한다


Product라는 클래스가 있다고 가정하자


다른 클래스를 ProductInfo 혹은 ProductData라 부른다면 개념을 구분하지 않은 채 이름만 달리한 경우다


Info나 Data는 a, an, the와 마찬가지로 의미가 불분명한 불용어다


요지는 zork라는 변수가 있다는 이유만으로 theZork라 이름지어서는 안된다는 말이다


불용어는 중복이다


변수 이름에 variable이라는 단어는 단연코 금물이다


표 이름에 table이라는 단어도 마찬가지다


NameString이 Name보다 뭐가 나은가?


Name이 부동 소수가 될 가능성이 있던가?


그렇다면 앞서 언급한 그릇된 정보를 피하라 규칙을 위반한다


Customer라는 클래스와 Customer Object라는 클래스를 발견했다면 차이를 알겠는가?


고객 급여 이력을 찾으려면 어느 클래스를 뒤져야 빠를까?


이와 같은 오류를 저지르는 애플리케이션이 있다


개발자를 보호하고자 이름을 바꿨으나 오류 형태는 정확히 다음과 같다


getActiveAccount( );


getActiveAccounts( );


getActiveAccountInfo( );



명확한 관례가 없다면 변수 moneyAmount는 money와 구분이 안 된다


custormerInfo는 custorer와, accountData는 



2020. 11. 3. 20:36

프로그래머는 코드에 그릇된 단서를 남겨서는 안 된다


그릇된 단서는 코드 의미를 흐린다


나름대로 널리 쓰이는 의미가 있는 단어를 다른 의미로 사용해도 안 된다


여러 계정을 그룹으로 묶을 때, 실제 List가 아니라면 accountLIst라 명명하지 않는다


프로그래머에게 List는 특수한 의미다


계정을 담는 컨테이너가 실제 List가 아니라면 프로그래머에게 그릇된 정보를 제공하는 셈이다


그러므로 accountGroup, bunchOfAccounts, 아니면 단순히 Accounts라 명명한다


서로 흡사한 이름을 사용하지 않도록 주의한다


한 모듈에서 XYZControllerForEfficientHandlingOfStrings라는 이름을 사용하고, 


조금 떨어진 모듈에서 XYZControllerForEfficientStorageOfStrings 라는 이름을 사용한다면? 


차이를 알아챘는가?


두 단어는 겁나게 비슷하다


유사한 개념은 유사한 표기법을 사용한다


이것도 정보다


일관성이 떨어지는 표기법은 그릇된 정보다


십중팔구 개발자는 이름만 보고 객체를 선택한다

2017. 11. 9. 19:32

이름을 잘 짓는 간단한 규칙


1. 의도를 분명히 밝혀라


- 좋은 이름을 지으려면 시간이 걸리지만 좋은 이름으로 절약하는 시간이 훨씬 많다


- 변수나 함수 그리고 클래스 이름은 다음과 같은 질문에 모두 대답 가능


1. 존재 이유

2. 수행 기능

3. 사용 방법


- 따로 주석이 필요하다면 의도를 분명히 드러내지 못함


int d; // 경과 시간(단위 : 날짜)


이름 d는 아무 의미도 드러나지 않는다


- 측정하려는 값과 단위를 표현하는 이름이 필요하다


int elapsedTimeInDays;


int daysSinceCreation;


int daysSinceModification;


int fileAgeInDays;


의도가 드러나는 이름을 사용하면 코드 이해와 변경이 쉬워진다



다음 코드는 무엇을 할까?


public vector<int*> getThem() {

    vector<int*> list1;

    for(auto x : theList)

        if(x[0] == 4)

            list1.push_back(x);

    return list1;

}


코드가 하는 일을 짐작하기 어렵다


왜일까? 복잡한 문장은 없다


공백과 들여쓰기도 적당하다


변수는 세 개, 상수는 두 개 뿐이다


화려한 클래스나 다형성 메서드도 없다


단지 배열 목록만 사용한다


문제는 코드의 단순성이 아니라 코드의 함축성이다


다시 말해 코드 맥랙이 코드 자체에 명시적으로 드러나지 않는다


위 코드는 암암리에 독자가 다음과 같은 정보를 안다고 가정한다


1. theList에 무엇이 들어있는가?


2. theList에서 0번째 값이 어째서 중요한가?


3. 값 4는 무슨 의미인가?


4. 함수가 반환하는 리스트 list1을 어떻게 사용하는가?



위 코드 샘플엔 이와 같은 정보가 드러나지 않는다


하지만 정보 제공은 충분히 가능했었다


지뢰찾기 게임을 만든다고 가정하자


그러면 theList가 게임판이라는 사실을 안다


theList를 gameBoard로 바꿔보자


게임판에서 각 칸은 단순 배열로 표현한다


배열에서 0 번째 값은 칸 상태를 뜻한다


값 4는 깃발이 꽂힌 상태를 가리킨다


각 개념에 이름만 붙여도 코드가 상당히 나아진다



public vector<int*> getFlaggedCells( ) {

    vector<int*> flaggedCells;

     for(auto cell : gameBoard)

        if(cell[STATUS_VALUE] == FLAGGED)

            flaggedCells.push_back(cell);

    return flaggedCells;

}



연산자 수와 상수 수는 똑같다


그런데도 코드는 더욱 명확해졌다


한 걸음 나아가 int 배열을 사용하는 대신, 칸을 간단한 클래스로 만든다


isFlagged라는 좀 더 명시적인 함수를 사용해 FLAGGED라는 상수를 감춰도 된다



public vector<Cell> getFlaggedCells( ) {

    vector<Cell> flaggedCells;

     for(auto cell : gameBoard)

        if(cell.isFlagged( ))

            flaggedCells.push_back(cell);

    return flaggedCells;

}


단순히 이름만 고쳤는데도 함수가 하는 일을 이해하기 쉬워졌다


이것이 좋은 이름이 주는 위력이다