LeeA0의 공부 일기

[Clean Code] 2장. 의미 있는 이름 본문

Java/Clean Code

[Clean Code] 2장. 의미 있는 이름

LeeA0 2021. 8. 29. 16:15

[사담]

더보기

이번 장부터 본격적인 클린 코드 작성방법이 나와서 좋았습니다.

코드의 예시까지 함께볼 수 있어서 좋았는데, 이해 안 되는 부분도 몇 있어서 그 부분만 여러 번 읽었네요 ㅎㅎ

규칙의 예시 중에 "젠 야무다 힘즈"가 너무 재밌었습니다..ㅋㅋㅋ

이름을 정할 땐 항상 조심해야겠네요~ㅎ

 

[정리]

<이름을 잘 짓는 간단한 규칙>

1. 의도를 분명히 밝혀라

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

- 존재 이유는?

- 수행 기능은?

- 사용 방법은?

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

 

<안 좋은 예시 1>

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

<좋은 예시 1>

int daysSinceCreation;
int daysSiceModification;

 

<안 좋은 예시 2>

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

위 예시를 알아보려면 다음과 같은 정보를 알아야 한다.

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

=> '지뢰 찾기 게임을 만든다고 가정, theList가 게임판, 배열에서 0번째 값을 깃발이 꽂힌 상태'로 가정

 

<좋은 예시 2>

public List<int[]> getFlaggedCells() {
    List<int[]> flaggedCells = new ArraysList<int[]>();
    for (int[] cell : gameBoard)
    	if (cell[STATUS_VALUE] == FLAGGED)
        	flaggedCells.add(cell);
    return flaggedCells;
}

이걸 더 수정해본다면, (Cell이라는 객체를 만들어 int[]를 대체, isFlagged라는 메서드를 만들어 상수를 감춤)

public List<Cell> getFlaggedCells() {
    List<Cell> flaggedCells = new ArraysList<int[]>();
    for (Cell cell : gameBoard)
    	if (cell.isFlagged())
        	flaggedCells.add(cell);
    return flaggedCells;
}

 

2. 그릇된 정보를 피하라

- 나름대로 의미 있는 단어를 다른 의미로 사용하면 안 됨

ex) hp, aix, sco

    -> 유닉스 플랫폼이나 유닉스 변종을 가리키는 이름)

ex) accountList

    -> 여러 계정을 그룹으로 묶을 때, 실제 List가 아니다.

    -> 프로그래머에게 List라는 단어는 특수한 의미

    -> accountGroup, bunchOfAccounts, Accounts가 낫다.

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

ex) XYZControllerForEfficientHandlingOfStrings / XYZControllerForEfficientStorageOfStrings

- 소문자 L (l)이나 대문자 O를 피해라

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

 

3. 의미 있게 구분하라

- 컴파일러나 인터프리터만 통과하려는 생각으로 코드를 구현하는 것 X

ex) class라는 변수 -> klass (끔찍..)

- 연속된 숫자를 덧붙이거나 불용어를 추가하는 방식은 적절하지 않음

ex) a1, a2, ..., aN

ex) ProductInfo 혹은 ProductData -> Product와 다를 게 없다.

     그 밖에도 NameString/Name, theZork/zork, Customer/CustomerObject, ...

 

<안 좋은 예시>

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 destination[]) {
    for (int i = 0; i < source.length; i++) {
    	destination[i] = source[i];
    }
}

 

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

ex) genymdhms; generate date, year, month, day, hour, minute, second

    -> 회의 때마다 "젠 와이 엠 디 에이취 엠 에스" -> "젠 야 무다 힘즈"가 돼버리는 불상사가 발생한다.

    -> generationTimestamp (좀 더 지적인 대화가 가능해진다)

 

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

- 문자 하나를 사용하는 이름 혹은 상수는 검색하기 어렵다.

ex) 7 -> 7이 들어가는 모든 파일 이름, 수식이 다 검색된다.

    MAX_CLASSES_PER_STUDENT = 7 -> 이런 식으로 사용하면 변경도 쉽고, 검색도 쉽다.

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

 

<안 좋은 예시>

for (int j=0; i<34; j++) {
    s += (t[j]*4)/5;
}

<좋은 예시>

int realDaysPerIdealDay = 4;
const int WORK_DAYS_PER_WEEK = 5;
int sum = 0;
for (int j=0; j < NUMBER_OF_TASKS; j++) {
    int realTaskDays = taskEstimate[j] * realDaysPerIdealDay;
    int realTaskWeeks = (realTaskDays / WORK_DAYS_PER_WEEK);
    sum += realTaskWeeks;
}

-> 그냥 5보다 WORK_DAYS_PER_WEEK가 검색하기 훨씬 편하다!

 

6. 인코딩을 피하라

- 유형이나 범위 정보까지 인코딩에 넣으면 이름을 해독하기 어려워짐

ex) 헝가리식 표기법

    -> 윈도 C API - 정수 핸들, long 포인터, void 포인터, ...

    -> 옛날에는 컴파일러가 타입을 점검하지 않아 프로그래머에게 타입을 기억할 단서가 필요했음

    -> Java 프로그래머는 이럴 필요가 없다.

        (객체는 강한 타입이며, IDE는 코드를 컴파일하지 않고도 타입 오류를 감지한다.)

<좋은 예시>

PhoneNumber phoneString;

-> 타입이 바뀌어도 이름이 바뀌진 않는다!

 

ex) 멤버 변수 접두어

    -> 멤버 변수에 m_이라는 접두어를 붙일 필요 없다.

    -> 멤버 변수를 다른 색상으로 표시하거나 눈에 띄게 보여주는 IDE를 사용!

 

<안 좋은 예시>

public class Part {
    private String m_dsc;
    void setName(String name) {
    	m_dsc = name;
    }
}

<좋은 예시>

public class Part {
    private String description;
    void setDescription(String description) {
    	this.description = description;
    }
}

 

7. 인터페이스 클래스와 구현 클래스

- 인터페이스 이름에 접두어를 붙이지 않는 편이 좋음

ex) 도형을 생성하는 ABSTRACT FACTORY

인터페이스 클래스
Interface Class
구체 클래스
Concreate Class
IShapeFactory ( X ) ShapeFactory
ShapeFactory ShapeFactoryImp
ShapeFactory CShapeFactory

 

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

- 독자가 코드를 읽으면서 변수 이름을 자신이 아는 이름으로 변환해야 한다면 바람직하지 못한 변수명임

- 문제 영역이나 해법 영역에서 사용하는 이름을 선택

- 문자 하나만 사용하는 변수 이름은 문제가 있음

  but. 루프에서 반복 횟수를 세는 i, j, k는 가능 (l은 안되요!)

  -> 루프에서 반복 횟수 변수는 전통적으로 한 글자를 사용하기 때문

  -> a, b를 사용했으니 c를 선택한다는 억지 논리는 금물!

- 명료함이 최고

ex)

GOOD BAD
명료함이 최고인
전문가 프로그래머
r이 호스트와 프로토콜을 제외한 소문자 URL라는 것을 알고있는
똑똑한 프로그래머

 

- 클래스 이름은 명사나 명사구가 적합, Manager/Processor/Data/Info 등 사용 기피

- 메서드 이름은 동사나 동사구가 적합, 접근자 -> get, 변경자 -> set, 조건자 -> is를 붙임

 

<예시>

String name = employee.getName();
customer.setName("mike");
if (paycheck.isPosted()) ...

- 생성자를 정복정의할 때는 정적 팩토리 메서드를 사용

 

<안 좋은 예시>

Complex fulcrumPoint = new Complex(23.0);

<좋은 예시>

Complex fulcrumPoint = Complex.FromRealNumber(23.0);

9. 기발한 이름은 피하라

- 재미난 이름보다 명료한 이름

- 특정 문화에서만 사용하는 농담은 피해라

GOOD BAD
DeleteItems HolyHandGrenade
kill() whack()
Abort() eatMyShort()

 

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

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

ex1) fetch, retrieve, get

ex2) controller, manager, driver

 

11. 말장난을 하지 마라

- 한 단어를 두 가지 목적으로 사용하지 말 것

ex)

기존 값 두 개를 더하거나
이어서 새로운 값을 만듬
집합에 값 하나 추가
add add ( X )
add insert나 append ( O )

 

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

- 코드를 읽을 사람도 프로그래머

- 전산 용어, 알고리즘 이름, 패턴 이름, 수학 용어 등을 사용해도 괜찮음

ex) JobQueue, VISITOR패턴 -> AccountVisitor

 

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

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

 

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

- 클래스, 함수, 이름 공간에 넣어 맥락을 부여

- 모든 방법이 실패하면 최후의 수단으로 접두어를 붙임

ex)

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

-> 전체를 보면 주소라는 사실을 알 수 있다.

but. state라는 변수 하나만 사용한다면?

-> addr라는 접두어를 추가해 맥락을 분명히 한다.

addrFirstName, addrLastName, addrState, ...

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

 

<안 좋은 예시>

private void printGuessStatistics(char candidate, int count) {
    String number;
    String verb;
    String pluralModifier;
    if (count == 0) {
    	number = "no";
        verv = "are";
        pluralModifier = "s";
    } else if (count == 1) {
    	number = "1";
        verv = "is";
        pluralModifier = "";
    } else {
    	number = Integer.toString(count);
        verv = "are";
        pluralModifier = "s";
    }
    String guessMessage = String.format(
    	"There %s %s %s%s", verb, number, candidate, pluralModifier
    );
    print(guessMessage);
}

-> 함수를 끝까지 읽어야 통계 추측 메시지에 사용된다는 것을 알 수 있다.

-> 함수가 좀 길으므로 함수를 작은 조각으로 쪼갠다.

 

< 좋은 예시>

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);
        verv = "are";
        pluralModifier = "s";
    }
    
    private void thereIsOneLetter() {
        number = "1";
        verv = "is";
        pluralModifier = "";
    }
    
    private void thereAreNoLetters() {
    	number = "no";
        verv = "are";
        pluralModifier = "s";
    }
}

 

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

ex) 고급 휘발유 충전소; Gas Station Deluxe 애플리케이션

    -> 모든 클래스 이름을 GSD로 시작? -> G를 입력하고 자동 완성 키를 입력하면 모든 클래스가 나와버린다..!

    -> accountAddress와 customerAddress는 Address 클래스 인스턴스로는 좋지만, 클래스 이름으로는 적합하지 못함

    -> Account는 클래스 이름으로 적합!

    -> 만약, 포트 주소, MAC 주소, 웹 주소를 구분해야 한다면 PostalAddress, MAX, URI라는 이름도 괜찮다.

 

여느 코드 개선 노력과 마찬가지로 이름 역시 나름대로 바꿨다가는 누군가 질책할지도 모른다.
그렇다고 코드를 개선하려는 노력을 중단해서는 안된다.

 


 

 
 
Clean Code
저자 : 로버트 C. 마틴
출판 : 인사이트
발매 : 2013. 12. 24

'Java > Clean Code' 카테고리의 다른 글

[Clean Code] 3장. 함수 (미완)  (0) 2021.09.11
[Clean Code] 2장 - 실습  (0) 2021.09.02
[Clean Code] 1장. 깨끗한 코드  (0) 2021.08.22
[Clean Code] 0장. 들어가면서  (0) 2021.08.22
[Clean Code] 시작일기  (0) 2021.08.22
Comments