2장 의미 있는 이름

의도를 분명히 밝혀라

코드 맥락이 코드 자체에 명시적으로 드러나도록 이름에 정보를 표현해라

  • 나쁜 예

    days?, duration? d가 무엇인지 정확히 모른다. 주석이 필요하다. 경과 시간이라는 느낌이 안든다.

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

    int d; // 경과 시간(단위: 날짜)
  • 좋은 예

    경과시간, 생성 이후의 일수, 변경 이후의 일수, 파일 사용 기간라는 이름으로 의도가 명확히 드러나므로 독자(또 다른 개발자)가 읽기 편하다.

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

    int elapsdTimeInDays;
    int daysSinceCreation;
    int daysSinceModification;
    int fileAgeInDays;

그릇된 정보를 피하라

프로그래머는 코드에 그릇된 단서를 남겨서는 안 된다. 그릇된 단서는 코드 의미를 흐린다. 나름대로 널리 쓰이는 의미가 있는 단어를 다른 단어 사용해도 안된다.

  • 널리 쓰이는 의미가 있는 단어를 사용하지 마라

    ex) hp, aix, sco

    유닉스 플랫폼이나 유닉스 변종을 가리키는 이름으로 널리 쓰이는데, 직각삼각형의 빗변(hypotenuse)를 구현할 때는 hp가 훌륭한 약어로 보일지라도 hp라는 변수는 독자(다른 프로그래머)에게 그릇된 정보를 제공한다.

  • 그룹 변수 이름에 List를 사용하지 마라

    ex) accountListaccountGroup, bunchOfAccounts, Accounts

    실제 자료구조 List가 아니라면 잘못된 정보를 제공하는 셈이고, 실제 컨테이너가 List인 경우라도 컨테이너 유형을 이름에 넣지 않는 편이 바람직하다

  • 서로 흡사한 이름을 사용하지 마라

    ex) XYZController, ForEfficientHandling, XYZControllerForEfficientHandling

    단어가 너무나 비슷해서 각 이름별 차이를 잘 알지못한다.

  • 유사한 개념은 유사한 표기법을 사용해라

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

  • 이름으로 그릇된 정보를 제공하는 예

    ex) 소문자 L 과 숫자 1 : l vs 1 , 대문자 O와 숫자 0 O vs 0

의미 있게 구분하라

읽는 사람이 차이를 알도록 이름을 지어라.

  • 연속된 숫자로 이름을 구분하지 마라

    아무런 정보를 제공하지 못하는 이름이다.

    ex) copyChars(char a1[], char a2[])copyChars(char source[], char destination[])

  • 불용어로 이름을 구분하지 마라

    역시 아무런 정보를 제공하지 못한다.

    ex) Product | ProductInfo, ProductData, theProduct, aProduct, Products

    개념을 구분하지 않은 채 이름만 달리한 경우다.

    InfoDataa, an, the 와 마찬가지로 의미가 불분명한 불용어다.

    ex) SomethingManager | SomethingProcessor

  • 불용어는 중복이다. 중복되지 않게 이름을 잘짓자

    • NameString -> Name

    • Customer, CustomerObject 둘의 차이를 알겠는가? 차이를 구분하도록 중복되지 않게 이름을 짓자

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

발음하기 쉬운 이름은 중요하다. 프로그래밍은 사회 활동이기 때문이다.

  • 나쁜 예

    • genymdhms(generate date, year, month, day, hour, minute, second)

      발음하기 어려운 이름은 토론하기도 어렵다. 바보처럼 들리기 십상이다. 실제로 이러한 단어가 있고 "젠 와이 엠 디 에이취 엠 에스", "젠 야 무다 함즈"라고 발음했다고 한다.

  • 좋은 예

    • GenerationTimestamp

      지적인 대화가 가능해진다. "마이키, 이 레코드 좀 보세요. Generation Timestamp 값이 내일 날짜입니다! 어떻게 이렇죠?"

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

검색을 통해 사용 위치를 쉽게 확인할 수 있는 의미있는 이름을 지어라.

  • 긴 이름이 짧은 이름보다 좋다.

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

    • MAX_CLASSES_PER_STUDENT 과 숫자 7을 비교해보라. 무엇이 더 검색하기 쉬운가?

      상수에 버그가 있으나 검색으로 찾아내지 못한다.

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

    변수나 상수를 코드 여러 곳에서 사용한다면 검색하기 쉬운 이름이 바람직하다.

인코딩을 피하라

이름에 불필요한 정보를 추가하지 말고 IDE를 활용하라.

  • 헝가리식 표기법 : 변수 이름에 타입을 붙이지 말자

    PhoneNumber phoneString;
    // 타입이 바뀌어도 이름은 바뀌지 않는다!
  • 멤버 변수 접두어 m_ : 이제는 붙일 필요가 없다.

    클래스와 함수는 접두어가 필요없을 정도로 작아야하며 멤버 변수를 다른 색상으로 표시해주는 IDE를 사용해야한다.

  • 인터페이스 클래스와 구현 클래스 : 예외로, 구체 클래스(concrete class)에 Impl 접미어 인코딩은 필요하다.

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

남들이 이해하는 이름을 사용해라

  • URL 변수인데 이름을 r 이라고 하고 짓지 말자

    즉, 자신의 기억력이 좋다고 자신하며 r이라고 짓지 말자

  • 문자 하나만 사용하는 변수 이름은 문제가 있다. (루프에서 반복 횟수를 세는 변수 i, j, k는 괜찮다. l 은 절대 안 된다.)

    독자가 실제 개념으로 변환해야하는 불필요함을 주기 때문이다.

클래스 이름

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

  • 좋은 예

    • Customer, WikiPage, Account, AddressParser

  • 나쁜 단어

    • Manager, Processor, Data, Info

메서드 이름

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

생성자를 중복정의(overload)할 때는 정적 팩토리 메소드를 사용한다.

  • 좋은 예

    Complex fulcrumPoint = Complex.FromRealNumber(23.0);
  • 나쁜 예

    Complex fulcrumPoint = new Complex(23.0);

기발한 이름은 피하라

재미난 이름보다 명료하고 분명한 이름을 선택하라.

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

추상적인 개념 하나에 단어 하나를 선택해 이를 고수하자.

메서드 이름은 독자적이고, 일관적이어야 한다.

  • ex) 똑같은 메서드를 클래스마다 fetch, retrieve, get 으로 제각각 부르면 혼란스럽다.

    어느 클래스에서 어느 이름을 썼는지 기억하기 어렵다. 따라서 동일 기능의 메서드이면 하나의 이름만 사용하자.

  • ex) 동일 코드 기반에 controller, manager, driver를 섞어 쓰면 혼란스럽다. DeviceManager, ProtocolController는 근본적으로 어떻게 다른가? 어째서 둘 다 Controller가 아닌가? 어째서 둘 다 Manager 가 아닌가? 이름이 다르면 독자는 당연히 클래스도 다르고 타입도 다르다고 생각한다.

말장난을 하지 마라(한 단어를 두 개념에 사용하지 마라)

  • 한 단어를 두 가지 목적으로 사용하지 마라. 다른 개념에 같은 단어를 사용한다면 그것은 말장난에 불과하다.

  • ex) addappend

    • 예를 들어, 지금까지 구현한 add 메서드는 모두가 기존 값 두개를 더하거나 이어서 새로운 값을 만든다고 가정하자.(ex. return a+b) 근데 새로 작성하는 메서드는 집합에 값 하나를 추가한다. add 라는 메서드가 많으므로 일관성을 지키려면 add라 불러야 하지 않을까? 하지만 새 메서드는 기존 add 메서드와 맥락이 다르다. 그러므로 insertappend 라는 이름이 적당하다. 새 메서드를 add라 부른다면 이는 말장난이다.

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

기술 개념에는 기술 이름을 붙이는 것이 가장 적합한 선택이다.

모든 이름을 문제 영역(domain)에서 가져오는 정책은 현명하지 못하다.

같은 이름(도메인용으로 사용되는 이름)을 다른 이름(기술용어로 사용되는 이름)으로 오해하던 동료들이 매번 물어봐야 하기 때문이다. 따라서 부담 갖지말고 코드를 읽는 사람도 프로그래머라는 사실을 명심하고, 전산용어, 알고리즘 이름, 패턴 이름, 수학 용어등을 사용하자.

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

적절한 프로그래밍 용어가 없다면 문제 영역(domain)에서 이름을 가져온다. 그러면 코드를 보수하는 프로그래머가 도메인 전문가에게 의미를 물어 파악할 수 있다.

의미 있는 맥락을 추가하라

스스로 의미가 분명한 이름도 있다. 하지만 대다수 이름은 그렇지 못하고 주변의 맥락을 파악해야 의미를 알아차리는 경우다. 그래서 클래스, 함수, 이름 공간에 넣어 맥락을 부여한다. 모든 방법이 실패하면 마지막 수단으로 접두어를 붙인다.

  • 예를 들어, firstName, lastName, street, houseNumber, city, state, zipcode라는 변수가 있다. 변수를 훑어보면 주소라는 사실을 금방 알아챈다. 하지만 어느 메서드가 state(주)라는 변수하나만 사용하면 state(상태)와 헷갈릴 가능성이 있다.

    1. addr라는 접두어를 추가해 addrFirstName, addrLastName, addrState라 쓰면 맥락이 좀 더 분명해진다.

    2. Address라는 클래스를 생성하면 더 좋다.

  • 맥락이 불분명한 변수

    private void printGuessStatistics(char candiate, 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);
    }

일단 함수가 좀 길다. 그리고 세 변수를 함수 전반에서 사용하다. 함수를 작은 조각으로 쪼개고자 GuessStaticsMessage라는 클래스를 만든 후 세 변수를 클래스에 넣었다. 그러면 세 변수는 맥락이 분명해진다. 즉, 세 변수는 확실하게 GuessStaticsMessage에 속하게 된다. 이렇게 맥락을 개선하면 함수를 쪼개기가 쉬워지므로 알고리즘도 좀 더 명확해진다.

  • 맥락이 분명한 변수

    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 thereAreNoLetters(){
    		number = "no";
    		verb = "are";
    		pluralModifier = "s";
    	}
    }

불필요한 맥락을 없애라

일반적으로 짧은 이름이 긴 이름보다 좋다. 단, 의미가 분명한 경우에 한해서다.(즉, 의미가 분명하지 않은 대부분의 경우에는 긴 이름이 좋다.)

accountAddress와 customerAddress 는 Address 클래스 인스턴스로는 좋은 이름이나 클래스 이름으로는 적합하지 못하다. Address는 클래스 이름으로 적합하다. 포트 주소, MAC 주소, 웹 주소를 구분해야 한다면 PostalAddress, MAC, URI라는 이름도 괜찮겠다.

  • 불필요한 맥락이 포함된 경우들

    • 고급 휘발유 충전소(Gas Station Deluxe)라는 애플리케이션을 짠다고 모든 클래스 이름을 GSD라고 시작하는 경우

      ⇒ GSD를 붙이는게 무슨 의미가 있을까? IDE에서 클래스 이름을 검색하려고 G를 누르면 모든 클래스를 열거한다.

Last updated