도서 요약 / / 2022. 12. 19. 09:54

[클린 코드] 2. 의미 있는 이름

클린 코드 도서 요약 내용입니다.

2장 의미 있는 이름

들어가면서

소프트웨어에서 이름은 어디나 쓰인다.

  • 변수, 함수, 인수와 클래스, 패키지, 소스파일, 디렉토리, jar파일, war파일, ear 파일
  • 이 장에서는 이름을 잘 짓는 간단한 규칙을 몇가지 소개한다.
의도를 분명히 밝혀라
  • 의도가 분명한 이름이 정말로 중요하다는 사실을 거듭 강조한다.
  • 좋은 이름을 지으려면 시간이 걸리지만 좋은 이름으로 절약하는 시간이 훨씬 더 많다.

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

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

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

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

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

다음 코드는 무엇을 할까?

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

코드가 하는 일을 짐작하게 어렵다. 복잡한 문장은 없다.

문제는 코드의 단순성이 아니라 코드의 함축성이다. 코드 맥락이 코드 자체에 명시적으로 드러나지 않는다.

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

이를 조금 더 개선하면

public Likst<Cell> getFlaggedCells() {
  List<Cell> flaggedCells = new Arraylist<Cell>();
  for (Cell cell : gameBoard)
        if (cell.isFlagged())
            flaggedCells.add(cell);
  return flaggedCells;
}

단순히 이름만 고쳤는데도 함수가 하는 일을 이해하기 쉬워졌다. 바로 이것이 좋은 이름이 주는 위력이다.

그릇된 정보를 피하라
  • hp, aix, sco는 변수 이름을 적합하지 않다.
  • 실제 List가 아니라면 accountList라 명명하지 않는다.
  • 서로 흡사한 이름을 사용하지 않도록 주의한다.
    • 한 모듈에서 XYXControllerForEfficientHandlingOfStrings라는 이름을 사용하고 다른 모듈에서 XYXControllerForEfficientStorageOfStrings라는 이름을 사용한다면 그 차이는?
  • 유사한 개념은 유사한 표기법을 사용한다.
  • 소문자 L이나 대문자 O변수다.
  • 소문자 L은 숫자 1처럼 보이고 대문자 O는 숫자 0처럼 보인다.
int a = 1;
if (O == 1)
  a == O1;
else
  1 = 01;
의미 있게 구분하라
public static void copyChars(char a1[], char a2[]) {
  for (int i=0; i < a1.length; i++) {
      a2[i] = a1[i];
  }
}
  • 함수 인수 이름으로 source, destination을 사용한다면 코드 읽기가 훨씬 더 쉬워진다.
  • 불용어를 추가한 이름 역시 아무런 정보를 제공하지 못한다.
  • Product라는 클래스, ProductInfo, ProductData라 부른다면 Info나 Data는 a, an, the와 마찬가지로 의미가 불분명한 불용어다.
  • 불용어를 사용하지 말라는 이야기는 아니다.
  • zork라는 변수가 있다는 이유만으로 theZork라 이름 지어서는 안된다는 말이다.
  • 불용어는 중복이다. variable, table이라는 단어도 마찬가지다.
  • NameString이 Name보다 뭐가 나은가?
  • Customer와 CustomerObject의 차이를 알겠는가?
getActiveAccount();
getActiveAccounts();
getActiveAccountInfo();
  • 명확한 관계가 없다면 변수 moneyAmount와 money는 구분이 안된다.
  • customerInfo와 customer, accountData는 account와, theMessage와 message와 구분이 안 된다.
  • 읽는 사람이 차이를 알도록 이름을 지어라.
발음하기 쉬운 이름을 사용하라
class DtaRcrd102 {
  private Date genymdhms;
  private final String pszqint = "102";
}

젠 와이 엠 디 에이취 엠 에스

public Customer {
  private Date generationTimestamp;
  private Date modificationTimestamp;
  private final String recordId = "102";
}
검색하기 쉬운 이름을 사용하라
  • MAX_CLASS_PER_STUDENT는 grep으로 찾기가 쉽지만, 숫자 7은 은근히 까다롭다.
  • e라는 문자도 변수 이름으로 적합하지 못하다.
  • 개인적으로는 간단한 메서드에서 로컬 변수만 한 문자를 사용한다.
for (int j=0; j<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_TAKS; j++) {
  int realTaskDays = taskEstimate[j] * realDaysPerIdealDay;
  int realTaskWeeks = (realTaskDays / WORK_DAYS_PER_WEEK);
  sum += realTaskWeeks;
}

위의 코드에서 WORK_DAYS_PER_WEEK를 찾기가 얼마나 쉬운지 생각해보라.

인코딩을 피하라
헝가리식 표기법
  • 포트란은 첫 글자로 유형을 표현했다.
  • 초창기 베이식은 글자 하나에 숫자 하나만 허용했다.
  • 과거 윈도 C API는 헝가리식 표기법을 굉장이 중요하게 여겼다.
  • 자바 프로그래머는 변수 이름에 타입을 인코딩할 필요가 없다.
PhoneNumber phoneString;
// 타입이 바뀌어도 이름은 바꾸지 않는다.
멤버 변수 접두어

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

public class Part {
  private String m_dsc; // 설명 문자열
  void setName(String name) {
    m_dsc = name;
  }
}
public class Part {
  String description;
  void setDescription(String description) {
    this.description = description;
  }
}
인터페이스 클래스와 구현 클래스
  • 인터페이스 클래스와 구현 클래스. IShapeFactory와 ShapeFactory?
  • 개인적으로 인터페이스 이름은 접두어를 붙이지 않는 편이 좋다고 생각한다.
  • 옛날 코드에서 많이 사용하는 접두어 I는 주의를 흐트리고 과도한 정보를 제공한다.
  • 차라리 구현 클래스에 붙이는 것이 낫다. (ShapeFactoryImp나 CShapeFactory가 IShapeFactory보다 좋다)
자신의 기억력을 자랑하지 마라
  • 문자 하나만 사용하는 변수 이름은 문제가 있다.
  • 루프에서 반복 횟수를 세는 변수 i,j,k는 괜찮다. (l은 절대 안된다)
  • r이라는 변수가 호스트와 프로토콜을 제외한 소문자 URL이라는 사실을 기억한다면 확실히 똑똑한 사람이다.
  • 전문가 프로그래머는 명료함이 최고라는 사실을 이해한다.
클래스 이름
  • 클래스 이름과 객체 이름은 명사나 명사구가 적합하다.
  • Customer, WikiPage, Account, AddressParser 등이 좋은 예다.
  • Manager, Processor, Data, Info 등과 같은 단어는 피하고 동사는 사용하지 않는다.
메서드 이름
  • 메서드 이름은 동사나 동사구가 적합하다.
  • postPayment, deletePage, save 등이 좋은 예다.
  • 접근자, 변경자, 조건자는 javabean 표준에 따라 값 앞에 get, set, is를 붙인다.
String name = employee.getName();
customer.setName("mike");
if (paycheck.isPosted()) ...
기발한 이름은 피하라
  • HolyHandGrenade라는 함수가 무엇을 하는지 알겠는가? 기발한 이름이지만 DeleteItems가 더 좋다.
  • kill대신 whack()이나 abort() 대신 eatMyShort()라 부른다.
한 개념에 한 단어를 사용하라
  • 똑같은 메서드를 클래스마다 fetch, retrieve, get으로 부르면 혼란스럽다.
  • 동일 코드 기반에 controller, manager, driver 섞어 쓰면 혼란스럽다.
말장난을 하지 마라
  • 한 단어를 두 가지 목적으로 사용하지 마라. 다른 개념에 같은 단어를 사용한다면 그것은 말장난에 불과하다.
  • add 메서드: 기존 값 두 개를 더하거나 새로운 값을 만든다고 가정
  • 새로 작성하는 메서드 집합에 값 하나 추가 <-- 이 메서드를 add라 불러야 할까? Insert, append일까?
해법 영역에서 가져온 이름을 사용하라
  • 전산 용어, 알고리즘 이름 ,패턴 이름, 수학 용어 등을 사용해도 괜찮다.
  • AccountVisitor, JobQueue
문제 영역에서 가져온 이름을 사용하라.
  • 적절한 '프로그래머 용어'가 없다면 문제 영역에서 이름을 가져온다.
  • 문제 영역 개념과 관련이 깊은 코드라면 문제 영역에서 이름을 가져와야 한다.
의미 있는 맥락을 추가하라
  • state가 주소의 일부라는 것을 알까?
  • addrFirstName, addrLastName, addrState라 쓰면 맥락이 좀 더 분명해진다.
불필요한 맥락을 없애라
  • 고급 휘발유 충전소(Gas Station Deluxe)라는 애플리케이션을 짠다고 가정하자.
  • 모든 클래스 이름을 GSD로 시작하겠다는 생각은 전혀 바람직하지 못하다.
  • accountAccount와 customerAddress는 Address 클래스 인스턴스로는 좋은 이름이나 클래스 이름으로는 적합하지 못하다.
  • Address는 클래스 이름으로 적합하다.
마치면서
  • 좋은 이름을 선택하려면 설명 능력이 뛰어나야 하고 문화적인 배경이 같아야 한다. 이것이 제일 어렵다.
  • 좋은 이름을 선택하는 능력은 기술, 비즈니스, 관리 문제가 아니라 교육 문제다.
반응형
  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유
  • 카카오스토리 공유