Published on

2장. 의미 있는 이름

2장. 의미 있는 이름

의도를 분명히 밝혀라

변수, 함수, 클래스는 다음과 같은 질문에 모두 답이 되어야 합니다.

  • 존재 이유는?
  • 수행 기능은?
  • 사용 방법은?

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

  • 나쁜 예
int d; // 경과 시간 (단위: 날짜)
  • 좋은 예
int elapsedTimeInDays;
        int daysSinceCreation;
        int daysSinceModification;
        int fileAgeInDays;

아래 예제는 어떤걸 하는 로직일까요?

public List<int[]>getThem(){
        List<int[]>list1=new ArrayList<>();

        for(int[]x:theList){
        if(x[0]==4){
        list1.add(x);
        }
        }
        return list1;
        }

위 로직을 보면 의문점이 몇가지 들겁니다.

  • theList가 뭐지?
  • theList의 0번째가 뭔데 4랑 비교를하지?
  • 4는 또 뭐지?
  • 여기서 반환되는 List는 어떤 용도로 사용되지?

사실 위 코드는 지뢰찾기 게임입니다.

0번째 값은 칸 상태를 의미하고, 4는 깃발이 꽂힌 상태를 가리킵니다.

이에 맞게 네이밍을 변경해 보겠습니다.

public List<int[]>getFlaggedCells(){
        List<int[]>flaggedCells=new ArrayList<>();

        for(int[]cell:gameBoard){
        if(cell(STATUS_VALUE)==FLAGGED){
        flaggedCells.add(cell)
        }
        }
        return flaggedCells;
        }

0, 4 같은 값을 상수로 따로 정의하여 이름을 부여하면 훨씬 의미를 이해하기 쉽습니다.

위 로직에서 조건문에 들어가는 값은 따로 함수로 빼서 이름을 지어주는 편이 더 가독성이 좋습니다.

if(cell.isFlagged());

이처럼 네이밍을 잘하는 것은 코드를 이해하는데 무척이나 도움이 되며 개발 속도도 향상 됩니다.

네이밍을 고민하는데 시간이 오래걸리는 것 같아 대충 짓고 넘기고 싶을 때도 있지만, 나중에 그 코드를 다시 해석하는 시간이 네이밍 하는 시간보다 더 오래 걸릴 것이기 때문에

개발 속도를 향상시키기 위해서는 네이밍에 진심일 필요가 있습니다.

그릇된 정보를 피하라

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

빗변(hypoenuse)의 변수 이름으로 hp가 괜찮아 보이나, hp는 유닉스 플랫폼을 가리키기 때문에 오해의 소지가 있습니다. (저는 노트북 생각났습니다.)

또한, 실제 List 타입이 아닌 경우 xxxList 같은 형식은 피해야 합니다. 개발자에게 List는 특수한 의미이기 때문입니다.

계정을 담는 컨테이너의 경우 accountList 보다는 accountGroup, accounts, bunchOfAccounts 같은 네이밍이 더 좋습니다.

유사한 네이밍을 사용하지 않도록 주의해야 합니다.

XYZControllerForEfficientHandlingOfStrings
XYZControllerForEfficientStorageOfStrings

두 클래스의 차이를 네이밍만 보고 유추할 수 있을까요?

대부분의 개발자는 네이밍을 보고 객체를 선택합니다.

  • getXxx -> 가져오겠구나
  • setXxx -> 값을 변경 하겠구나

처럼 말이죠. 그래서 유사한 네이밍을 사용하지 않도록 주의해야 합니다.

추가로 O, L(소문자)만 사용하는 변수명은 피하는게 좋습니다

숫자 0, 1과 너무 흡사하기 때문에 글자체를 바꾼다고 하더라도 헷갈리기 쉽습니다.

의미 있게 구분하라

변수명에 숫자만 덧붙이는 (account1, account2, account3 ...) 방식같은 (불용어)는 좋지 않습니다.

컴파일러는 통과할지라도 나중에 소스를 고쳐야하는 상황이 오면 이해하기가 어렵습니다.

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

어떤 함수가 어떤 역할을 할지 감이 오시나요?

Custom, CustomObject 두 객체의 차이가 어떤건지 감이 오시나요?

아마도 비슷하지만 뭔가 조금 다른 내용 때문에 이렇게 지었을거라 생각합니다.

그 순간 네이밍이 떠오르지 않아서 급한대로 넘긴것이죠.

이제는 이런식의 네이밍은 하지 않도록 주의해야 합니다.

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

우리 두뇌에서 상당 부분은 단어라는 개념만 전적으로 처리합니다.

즉, 발음하기 쉬운 이름을 선택해야 이해하기도 쉽고 대화하기도 쉽습니다.

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

문자 하나를 사용하는 이름과 상수는 쉽게 눈에 띄지 않는다는 문제점이 있습니다.

MAX_CLASES_PER_STUDENT는 찾기 쉽지만 7은 찾기가 어렵습니다. 7이 포함된 모든 파일이나 수식이 검색되기 때문입니다.

또한, e도 찾기가 어렵습니다.

e는 영어에서 가장 많이 사용되는 문자이기 때문입니다.

대뜸 값으로 사용하기 보다 상수로 빼서 이름을 부여하여 사용하는 식이 검색하여 찾기도 쉽고 코드를 이해하는데도 좋습니다.

인코딩을 피하라

  • 헝가리안 표기식 X
  • 멤버 접두어 X

인터페이스와 구현 클래스 중 하나가 인코딩이 필요하다면 구현 클래스를 인코딩한다

ex) Shop(인터페이스), ShopImpl(구현체)

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

a, b, c 같은 변수명은 자신만 알 수 있습니다.

물론 반복문에서 i, j, k는 괜찮습니다 (단, 이때도 l은 안됨)

이 처럼 자신만 알 수 있는 변수명 대신 모두가 단번에 알아 볼 수 있도록 네이밍을 하는 것이 좋습니다.

클래스 이름

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

메서드 이름

메서드 이름은 동사동사구가 적합합니다.

  • 접근자: getXxx
  • 변경자: setXxx
  • 조건자: isXxx

생성자를 중복정의할 떄는 정적 팩토리 메서드를 사용하는 것이 좋습니다.

메서드 명은 인수를 설명하는 이름으로 사용합니다.

Complex.fromRealNumber(23.0);
        new Complex(23.0);

위에 버전이 아래 버전 보다 좋습니다.

기발한 이름은 피하라

기발한 이름은 저자와 유머감각이 비슷한 사람만 그리고 농담을 기억하는 동안만 이름을 기억합니다.

의도를 분명하고 솔직하게 표현하는것이 좋습니다.

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

똑같은 메소드 명 (fetch, retrieve, get 등)을 각 클래스마다 다른 의미로 사용하면 혼란스럽습니다.

일관성있게 사용하는 것이 좋습니다.

말장난 하지 마라

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

한 개념에 한 가지 단어만 사용하라 규칙을 따라서 여러 클래스에 add 라는 메소드가 생겼다고 가정해 봅시다.

여기서 add는 두 인자를 더하는 함수였습니다.

그런데 이번에는 List에 값을 추가하는 메소드를 만들어야하는데, 지금까지 add를 사용했으니 일관성을 위해 add라고 짓는것이 더 나은가? 라고 생각할 수 있지만 이렇게 되면 헷갈리게 됩니다.

기존에 add가 더하기의 의미로 사용되고 있었다면

List에 값을 추가하는 행위는 insert나 append라고 짓는것이 더 좋습니다.

add가 의미적으로 틀린건 아니지만 다른 코드와 함께 보면 혼란스럽기 때문입니다.

우리는 코드를 이해하기 쉽게 작성해야 합니다.

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

전산 용어, 알고리즘 이름, 패턴 이름, 스학 용어 등을 사용해도 좋습니다.

기술 개념에는 기술 이름이 가장 적합한 선택입니다.

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

적절한 프로그래머 용어가 없다면 문제 영역에서 이름을 가져옵니다.

그러면 코드를 보수하는 프로그래머가 분야 전문가에게 의미를 물어 파악할 수 있습니다.

문제 영역 개념과 관련이 깊은 코드라면 문제 영역에서 이름을 가져오는 것이 더 바람직합니다.

의미 있는 맥락을 추가하라

클ㅐ스, 함수, 이름 공간에 넣어 맥락을 부여하지만 이런 방식으로도 의도 드러나지 않으면 마지막 수단으로 접두어를 붙입니다.

firstName, lastName, street, houseNumber, city, state, zipcode

위 변수들은 주소라는 사실을 알 수 있습니다.

하지만 state만 단독으로 사용된다면 주소의 일부라는 것을 알아차리기란 어렵습니다.

이럴 땐, addrState 처럼 접두어를 붙여 사용하는 것이 더 좋습니다.

물론 Address 클래스를 생성하면 더 좋습니다.

불필요한 맥락을 없애라

일반적으로 의도가 분명한 경우에 짧은 이름이 긴 이름보다 좋습니다.

고급 휘발유 충전소 라는 애플리케이션을 짜는데 모든 클래스 이름을 GSD로 시작하는 것은 굉장히 비효율적입니다.

IDE의 도움을 받아 특정 클래스를 찾으려고 해도 모두 붙어있기 때문에 무의미합니다.