JaeWon's Devlog
article thumbnail
반응형

클린코드(CleanCode)를 읽고 간략하게 정리한 글입니다.


2장. 의미 있는 이름

- 소프트웨어에서 이름은 어디에서나 사용된다. 이름을 잘 지은다면 여러모로 편하다.

1. 의도를 분명히 밝혀라

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

- 이름을 주의 깊게 살펴 더 나은 이름으로 개선한다면 코드를 읽는 사람은 조금 더 편하다.

- 변수, 함수, 클래스 이름은 다음과 같은 질문에 모두 답해야 한다.

  • 존재 이유는? 수행 기능은? 사용 방법은?
  • 따로 주석이 필요하다면 의도를 분명히 드러내지 못했다는 말이다.

1-1. 변수

  • 나쁜 예시
int a; // 사람 수(단위 : 명)

- 위 변수를 살펴보면 실제 의도는 사람 수를 표현하지만 a 라는 변수를 보면 아무 의미도 드러나지 않는다.

- 의도가 드러나는 단위를 표현하는 이름이 필요하다.

  • 좋은 예시
int memberCount; // 사람 수(단위 : 명)
int loginFailCount; // 로그인 실패 수

1-2. 코드

  • 나쁜 예시
public List<Integer> getList() {
    List<Integer> list = new ArrayList<>();
    Integer number;
    Random random = new Randmom();
    
    for(int i = 0; i< 6; i++) {
        number = random.nextInt(45) + 1;
        if(check(list,random)) {
            i--;
        }
        list.add(number);
    }
    
    return list;
}

- 위 코드를 보면 랜덤 수를 뽑아서 무언가 check 를 하고 List에 추가하거나 다시 반복하거나 하는 것까진 보인다.

- 그러나 정확히 이 메소드가 어떤 행위를 하는지 알 수 없다.

  • 좋은 예시
public List<Integer> getLottoNumbers() {
    List<Integer> lottoNumbers = new ArrayList<>();
    Integer randomLottoNumber;
    Random random = new Randmom();
    
    for(int i = 0; i< 6; i++) {
        randomLottoNumber = random.nextInt(45) + 1;
        if(validDuplicateNumber(lottoNumbers,randomLottoNumber)) {
            i--;
        }
        lottoNumbers.add(randomLottoNumber);
    }
    
    return lottoNumbers;
}

- 이제 다시 메소드를 살펴보면 로또 숫자를 얻으려는 메서드이며, 반복문을 통해 랜덤 숫자를 만들고 중복숫자 검증을 통해 다시 반복을 하던가 숫자를 저장하는 것을 코드로만 보고 확인할 수 있다.

- 이렇게 코드에 정보 제공을 충분히 해야 한다.

  • 코드 맥락이 코드 자체에 명시적으로 드러나야 한다.
  • 단순히 이름만 고쳐도 함수가 하는 일을 이해하기 쉬워야 한다.

2. 그릇된 정보를 피하라

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

- 널리 쓰이는 의미가 있는 단어를 다른 의미로 사용하면 안 된다.

  • 예를 들어, 직각삼각형의 빗변으로 표현할 때 "hp(hypotenuse)"는 훌륭한 약어일지라도 다른 누군가에게는 잘못된 정보를 제공한다.(hp라는 미국의 기업을 떠올릴 수 있다.)
  • 예를 들어, 여러 계정을 그룹으로 묶을 때, 실제 List 가 아니라면 accountList라 명명하면 안 된다.
    • 프로그래머에게는 List는 특수한 의미를 가진다.
    • 실제 List 가 아니라면 accountGroup, accounts 등 명명하는 것이 좋다.

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

- 유사한 개념은 유사한 표기법으로 사용한다.

  • 일관성이 떨어지는 표기법은 그릇된 정보이다.
  • IDE의 자동완성 기능은 주석까지 노출해 주지 않는다.

3. 의미 있게 구분하라

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

- 동일 범위 안에서 다른 두 개념에 같은 이름을 사용하지 못한다고 철자를 틀리게 적으면 안 된다.

- 연속된 숫자(a1, a2, a3...)를 덧붙이거나 불용어(noise word)를 추가하는 방식은 적절하지 못하다.

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

  • 나쁜 예시
public static void copyChars(char a1[], char a2[]) {
    for (int i = 0; i < a1.length; i++) {
       a2[i] = a1[i];
    }
}
  • 좋은 예시
public static void copyChars(char source[], char copyValue[]) {
    for (int i = 0; i < source.length; i++) {
       copyValue[i] = source[i];
    }
}

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

- 발음이 쉬운 이름을 사용해야 커뮤니케이션에 도움이 된다.

// Bad
class DtaRcrd102 {
    private Date genymdhms;
    private Date modymdhms;
    private final String pszqint = "102";
    /* ... */
};

// Good
class Customer {
    private Date generationTimestamp;
    private Date modificationTimestamp;
    private final String recordId = "102";
    /* ... */
};

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

- 문자 하나를 사용하는 이름과 상수는 텍스트 코드에서 쉽게 눈에 띄지 않는다는 문제점이 있다.

- 검색하기 쉬운 이름이 상수보다 좋다.

- 이름 길이는 범위 크기에 비례해야 한다.

- 예를 들어, "MAX_CLASSES_PER_SUTDENT"는 검색으로 쉽게 찾지만, 숫자 7은 찾기 어렵다.

6. 인코딩을 피하라.

- 유형이나 범위 정보까지 인코딩에 넣으면 그만큼 이름을 해독하기 어려워진다.

- 인코딩한 이름은 거의 발음하기 어려우며 오타가 생기기 쉽다.

- 최근에는 헝가리식 표기법이나 기타 이름에 타입을 표기하는 방식은 오히려 방해가 될 뿐이다.

6-1. 헝가리식 표기법

- 과거 컴파일러가 타입을 점검하지 않을 경우 변수에 타입을 나타내었다.

- Java(자바)는 변수 이름에 타입을 인코딩할 필요가 없다.

PhoneNumber phoneString; // 타입이 바뀌어도 이름은 바뀌지 않는다.

6-2. 멤버 변수 접두어

- m_등의 접두어를 붙일 필요가 없다.

// Bad
public class Part {
    private String m_dec; // 설명 문자열
    void setName(PString name) {
        m_dec = name;
    }
}

// Good
public class Part {
    private String description; // 설명 문자열
    void setDescription(String description) {
        this.description = description;
    }
}

6-3. 인터페이스 클래스와 구현 클래스

- 인터페이스 클래스와 구현 클래스의 관계라면 클래스 사용자가 쉽게 접근할 수 있는 이름으로 작성한다.

  • Bad : ShapeFactory implements IShapeFactory
  • Good : ShapeFactoryImpl implements ShapeFactory

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

- 다른 사람이 코드를 보았을 때, 머릿속으로 한번 더 생각해야 하는 변수명은 쓰면 안 된다.

- 자신이 아는 이름으로 변환하는 것이 아니라 명료한 단어를 선택하여 작성한다.

- 전문 가 프로그래머는 자신의 능력을 좋은 방향으로 사용해 남들이 이해하는 코드를 내놓는다.

8. 클래스 이름

- 클래스 이름과 객체 이름은 명사나 명사구가 적합하다.

- 예를 들어, Customer, WikiPage, Account, AddressParser 등이 좋은 예다.

- Manager, Processor, Date, Info와 같은 단어는 피하는 것이 좋다.(무슨 관리자이고 어떤 프로세서며 어떤 날짜인지 명확해야 한다.)

- 동사는 사용하지 않는다.

9. 메서드 이름

- 메서드 이름은 동사나 동사구가 적합하다.

- 예를 들어, postPayment, deletePage, save 등이 좋은 예다.

- 접근자, 변경자, 조건자는 get, set, is로 시작하자.(should, has 등도 가능)

- 생성자를 중복정의(overload) 할 경우 정적 팩토리 메서드를 사용한다.

  • Bad : Complex fulcrumPoint = new Complex(23.0);
  • Good : Complex fulcrumPoint = Complex.FromRealNumber(23.0);

- 생성자 사용을 제한하려면 해당 생성자를 private로 선언한다.

10. 기발한 이름은 피하라

- 재미난 이름보다 명료한 이름을 선택해야 한다.

- 특정 문화에서만 사용하는 농담은 피하고 의도를 분명히 하고 솔직하게 표현한다.

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

- 추상적인 개념 하나에 단어 하나를 선택한다.

- 예를 들어, 똑같은 메서드를 클래스마다 fetch, retriveve, get으로 제각각 작성하면 혼란스럽다.

  • 각 클래스에서 이름(name)을 가져오는 메서드를 작성할 때 각 클래스마다 fetchName(), getName() 등으로 작성하는 것이 아니라 모든 클래스에 getName()으로 통일한다.

- 일관성 있게 단어를 사용한다.

12. 말장난을 하지 마라

- 한 단어를 두 가지 목적으로 사용하면 안 된다.

- 같은 맥락이 아닌데도 일관성을 고려해 이름을 같게 하면 안 된다.

- 프로그래머는 코드를 최대한 이해하기 쉽게 짜야한다.

- 집중적인 생각이 필요한 코드가 아니라 대충 훑어봐도 이해할 코드 작성이 목표이다.

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

- 코드를 읽는 사람도 프로그래머이므로 전산 용어, 알고리즘 이름, 패턴 이름, 수학 용어 등을 사용해도 괜찮다.

- 기술 개념에는 기술 이름(jobQueue 등)이 가장 적합한 선택이다.

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

- 적절한 프로그래밍 용어가 없다면 문제 영역(도메인 관련 전문 이름)에서 이름을 가져와 사용한다.

- 우수한 프로그래머와 설계자라면 해법 영역과 문제 영역을 구분할 줄 알아야 한다.

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

- 스스로 의미가 분명한 이름도 존재하지만 대다수 그렇지 못하다.

- 그렇기 때문에 클래스, 함수, 이름 공간에 넣어 맥락을 부여한다.

  • state라는 이름만 보고 주소라고 유추하기 어렵다.
  • addr 접두어를 추가해서 addrState 라 사용하면 맥락이 조금 더 분명해진다.
  • 나쁜 예시
private void printGuessStatistics(char candidate, int count) {
    String number;
    String verb;
    String pluralModifier;
    
    if (count == 0) {
        number = "no";
        verb = "are";
        pluralModifier = "s";
    } else if (count == 1) {
        number = "1";
        verb = "is";
        pluralModifier = "";
    } else {
        number = Integer.toString(count);
        verb = "are";
        pluralModifier = "s";
    }
    
    String guessMessage = String.format("There %s %s %s%s", verb, number, candidate, pluralModifier);
    print(guessMessage);
}

- 함수의 이름은 맥락의 일부만 제공하며, 알고리즘이 나머지 맥락을 제공한다.

- 함수를 끝까지 읽어보고 나서야, number, verb, pluralModified라는 변수를 통해 "통계 추측" 메시지에 사용된다는 것을 알 수 있다.

- 결국 맥락을 유추하는 건 이 코드를 읽는 사람의 몫이 된다.

- 메서드만 훑어서는 변수의 의미가 불분명하다.

  • 좋은 예시
public class GuessStatisticsMessage {
    private String number;
    private String verb;
    private String pluralModifier;
 
    public String make(char candidate, int count) {
        createPluralDependentMessageParts(count);
        return String.format("There %s %s %s%s", verb, number, candidate, pluralModifier);
    }
 
    private void createPluralDependentMessageParts(int count) {
        if (count == 0) {
            thereAreNoLetters();
        } else if (count == 1) {
            thereIsOneLetter();
        } else {
            thereAreManyLetters(count);
        }
    }
 
    private void thereAreManyLetters(int count) {
        number = Integer.toString(count);
        verb = "are";
        pluralModifier = "s";
    }
 
    private void thereIsOneLetter(){
        number = "1";
        verb = "is";
        pluralModifier = "";
    }
 
    private void thereAreNoLetter(){
        number = "no";
        verb = "are";
        pluralModifier = "s";
    }
}

- 위와 같이 GuessStatisticsMessage라는 클래스를 만든 후 세 변수를 클래스에 넣으면 변수의 맥락이 분명해진다.

- 이렇게 맥락을 개선하면 함수를 쪼개기 쉬워지고 알고리즘도 더 명확해진다.

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

- 일반적으로 짧은 이름이 긴 이름보다 좋다. 단, 의미가 분명한 경우에 한해서이다.

- 이름에 불필요한 맥락을 추가하지 않도록 주의해야 한다.

- 예를 들어, accountAddress와 customerAddress는 Address 클래스 인스턴스로는 좋은 이름이지만 클래스 이름으로는 적합하지 못하다.(Address는 클래스 이름으로는 적합하다.)

17. 결론

- 좋은 이름을 선택하려면 설명 능력이 뛰어나야 하고 문화적인 배경이 같아야 한다.

- 사람들이 이름을 바꾸지 않으려는 이유는 다른 개발자가 반대할까 두려워서이다.

- 여느 코드개선 노력과 마찬가지로 이름 역시 나름대로 바꿨다가 누군가 질책할지도 모르지만 그렇다고 코드, 이름을 개선하려는 노력을 멈춰서는 안 된다.

- 다른 사람이 짠 코드를 손본다면 문제해결 목적으로 이름을 개선해야 한다.

반응형

'Study > CleanCode' 카테고리의 다른 글

[클린코드] 6장. 객체와 자료 구조  (0) 2023.10.25
[클린코드] 5장. 형식 맞추기  (0) 2023.10.22
[클린코드] 4장. 주석  (0) 2023.10.15
[클린코드] 3장. 함수  (1) 2023.10.14
[클린코드] 1장. 깨끗한 코드  (3) 2023.10.08
profile

JaeWon's Devlog

@Wonol

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!