[Clean Code] 의미있는 이름

의미있는 이름

0. 들어가면서

1. 의도를 분명히 밝혀라

=> 따로 주석이 필요하다면 의도를 분명히 드러내지 못했다는 말이다.

적절하지 않은 변수 이름

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

적절한 변수 이름

int elapsedTimeInDays;
int daysSinceCreation;
int daysSinceModification;
int fileAgeInDays;

=> 이름 d는 아무 의미도 드러내지 않는다. 경과 시간이나 날짜라는 느낌이 안 든다. 측정하려는 값(ex. elapsedTime)과 단위(ex. InDays)를 표현하는 이름이 필요하다.

적절하지 않은 코드

public List<int[]> getThem() {
    List<int[]> list1 = new ArrayList<>();
    for (int[] x: theList) {
        if (x[0] == 4)
            list1.add(x);
    }
    return list1;
}

이 코드의 문제는 다음과 같은 내용을 명시하지 않아 코드가 하는 일을 짐작하기 어렵다는 것이다.

  1. theList에 무엇이 들었는가?
  2. theList에서 0번째 값이 어째서 중요한가?
  3. 값 4는 무슨 의미인가?
  4. 함수가 반환하는 리스트 list1을 어떻게 사용하는가?

적절한 코드

지뢰찾기 게임을 만든다고 하자. theList를 게임판으로 하면 gameBoard가 된다. 각 칸은 단순 배열로 표현되고 배열에서 0번째 값을 칸의 상태를 뜻하게 하자. 값 4는 깃발이 꼿힌 상태라 하자. 그럼 위의 의미없는 코드가 아래와 같은 가독성 있는 코드로 탈바꿈하게 된다.

public List<int[]> getFlaggedCells() {
    List<int[]> flaggedCells = new ArrayList<>();
    for (int[] cell: gameBoard) {
        if (cell[STATUS_VALUE] != FLAGGED) { continue; }

        flaggedCells.add(cell);
    }
    return flaggedCells;
}

한 걸음 더 나아가 int 배열을 사용하는 대신, 칸을 간단한 클래스로 만들어도 되겠다. isFlagged라는 좀 더 명시적인 함수를 사용해 FLAGGED 라는 상수를 감춰도 좋겠다. 다음과 같이

public List<Cell> getFlaggedCells() {
    List<Cell> flaggedCells = new ArrayList<>();
    for (Cell cell: gameBoard) {
        if (!cell.isFlagged()) { continue; }

        flaggedCells.add(cell);
    }
    return flaggedCells;
}

==> 졸라 좋네.

2. 그릇된 정보를 피하라

이름으로 그릇된 정보를 제공하는 진짜 끔찍한 예가 소문자 L이나 대문자 O 변수다. 두 변수를 한꺼번에 사용하면 더욱 끔찍해진다. 다음 코드에서 보듯, 소문자 L은 숫자 1처럼 보이고 대문자 O는 숫자 0처럼 보인다.

int a = l;
if (O == l)
    a = O1;
else
    l = 01;

=> 코드 역할과 관련된 영어 키워드를 최대한 많이 알아야겠다.

3. 의미 있게 구분하라

불용어가 들어간 코드

public static void copyChars(char a1[], char a2[]) {
    for (int i = 0; i < a1.length; i++) {
        a2[i] = a1[i];
    }
}

=> 함수 인수 이름으로 sourcedestination을 사용한다면 코드 읽기가 훨씬 쉬워진다.

고친 코드

public static void copyChars(char[] source, char[] destination) {
    for (int i = 0; i < source.length; i++) {
        destination[i] = source[i];
    }
}

=> 훨씬 자연스럽네.

getActiveAccount();
getActiveAccounts();
getActiveAccountInfo();

=> 이 프로젝트에 참여한 프로그래머는 어느 함수를 호출할지 어떻게 알까?

명확한 관례가 없다면 변수 moneyAmountmoney와 구분이 안 된다. customerInfocustomer와, accountDataaccount와, theMessagemessage와 구분이 안 된다.

4. 발음하기 쉬운 이름을 사용하라

class DtaRcrd102 {
    private Date genymdhms;
    private Date modymdhms;
    private final String pszqint = "102";
}
    
class Customer {
    private Date generationTimestamp;
    private Date modificationTimestamp;
    private final String recordID = "102";
}

5. 검색하기 쉬운 이름을 사용하라

for(int j = 0; j < 34; j++) {
    s += (t[j] * 4) / 5;
}
int realDaysPerIdealDay = 4;
final int WORK_DAYS_PER_WEEK = 5;
int sumOfRealTaskWeeks = 0;
for(int j = 0; j < NUMBER_OF_TASKS; j++) {
    int realTaskDays = taskEstimate[j] * realDaysPerIdealDay;
    int realTaskWeeks = (realTaskDays / WORK_DAYS_PER_WEEK);
    sumOfRealTaskWeeks += realTaskWeeks;
}

6. 인코딩을 피하라

7. 자신의 기억력을 자랑하지 마라

8. 클래스 이름

9. 메서드 이름

10. 기발한 이름은 피하라

11. 한 개념에 한 단어를 사용하라

12. 말장난을 하지 마라

13. 해법 영역에서 가져온 이름을 사용하라

14. 문제 영역에서 가져온 이름을 사용하라

15. 의미 있는 맥락을 추가하라

16. 불필요한 맥락을 없애라