21
Clean Code Ch.2 의미 있는 이름 chois79 12722일요일

Clean code Chapter.2

Embed Size (px)

Citation preview

Page 1: Clean code Chapter.2

Clean CodeCh.2 의미 있는 이름

chois79

12년 7월 22일 일요일

Page 2: Clean code Chapter.2

이장에서 다룰 내용

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

• 변수, 함수, 인수, 클래스, 파일, package, jar, war 등...

• 이러한 이름을 잘 짓는 것이 중요하다

• 이해도를 높인다.

• 이름을 잘 짓는 방법은 무엇인가?

12년 7월 22일 일요일

Page 3: Clean code Chapter.2

의도를 분명히 밝혀라

• 의도가 분명한 이름을 사용하는 것이 중요하다

• 좋은 이름을 짓는데 걸리는 시간 < 좋은 이름으로 인해 절약하는 시간

• Why? 코드의 이해와 변경이 쉬워짐

• 변수, 함수, 클래스의 이름을 짓는 가이드

• 다음의 질문에 답할 수 있는 이름을 사용

• 존재 이유는?

• 수행 기능은?

• 사용 방법은?

• 만약 주석이 필요하다면, 의도를 제대로 표현하지 못한 것

12년 7월 22일 일요일

Page 4: Clean code Chapter.2

의도를 분명히 밝혀라 - 예제

의도가 모호한 코드 의도가 분명한 코드

int 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 List<int[]> getFlaggedCells() { List<int []> flaggedCells = new ArrayList<int []>(); for(int [] cell: gameBoard) { if(cell[STATUS_VALUE] == FLAGGED) flaggedCells.add(cell); } return flaggedCells; }

// int []을 Cell Class로 변환 public List<Cell> getFlaggedCells() { List<Cell> flaggedCells = new ArrayList<Cell>(); for(Cell cell: gameBoard) { if(cell.isFlagged()) flaggedCells.add(cell); } return flaggedCells; }

12년 7월 22일 일요일

Page 5: Clean code Chapter.2

그릇된 정보를 피하라

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

• 일반적으로 사용되는 의미와 다르게 사용하면 안됨

• ex) 여러 계정을 그룹으로 묶을때 실제로 List 컨테이너가 아닌데 accountList 로 칭할 경우

• accountGroup, bunchOfAccounts 혹은 Accounts로 명명

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

• XYZControllerForEfficientHandlingOfStrings, XYZControllerForEfficientStorageOfString

• 유사한 개념은 유사한 표기법 사용

• 알파벳에 의한 모호성 주의

• 소문자 L과 숫자 1: l, 1

• 대문자 O와 숫자 0: O, 0

12년 7월 22일 일요일

Page 6: Clean code Chapter.2

의미 있게 구분하라

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

• 연속된 숫자를 사용하여 이름을 짓지마라

• 불용어를 사용하여 구분하지마라

• ex1) Info나 Data는 a, an, the와 마찬가지로 의미가 불분명

• ProductInfo, ProductData (차이점이 모호함)

• ex2) NameString과 Name, moneyAmount와 money, customerInfo와 customer

// a1, a2보다 source, destination 을 사용하여 가독성을 높일수 있음 public static void copyChars(char a1[], char a2[]) { for(int i = 0; i < a1.length; i++) { a2[i] = a1[i]; } }

12년 7월 22일 일요일

Page 7: Clean code Chapter.2

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

• 발음하기 어려운 이름은 의사 소통을 힘들게 한다

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

• 이 이름에 대해 어떻게 의사 소통 해야 하는가?

• “젠 와이 엠 디 에이취 엠 에스”, “젠 야 무다 힘즈”

발음하기 어려운 이름 발음하기 쉬운 이름

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

/* 코드를 통한 지적인 대화가 가능 */ class Customer { private Date generationTimestamp; private Date modificationTimestamp; private final String recordId = "102"; /* ... */ }

12년 7월 22일 일요일

Page 8: Clean code Chapter.2

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

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

• 문자 하나를 사용하는 이름과 상수는 가독성을 떨어뜨린다

• 간단한 메소드에서 로컬 변수만 한 문자를 사용

• 이름을 의미 있게 지으면 함수가 길어지지만 찾기가 쉽다

검색하기 어려운 이름 검색하기 쉬운 이름

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

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

12년 7월 22일 일요일

Page 9: Clean code Chapter.2

인코딩을 피하라

• 부담을 더하지 않아도 이름에 인코딩할 정보는 아주 많다

• 인코딩한 이름은 발음하기 어렵다

• 헝가리안 표기법 (윈도우 C API 표기법)

• 특징: 당시 컴파일러가 타입을 점검하지 않았기 때문에 타입을 변수명에 명시한 표기법

• 현대적 IDE는 컴파일 하지 않아도 타입을 감지하기 때문에 오히려 방해가 됨

• 클래스 이름이나 타입을 바꾸는 것이 어렵고, 읽기도 어렵다

• 멤버 변수 접두어

• 멤버 변수에 m_ 이라는 접두어를 붙이는 것보다 다른 색으로 표시해 주는 IDE 툴 사용

• 인터페이스 클래스와 구현 클래스

• 인터페이스에 접두어 ‘I’를 붙이는 것 보다 구현 클래스에 ‘C’ or 접미어 ‘Imp’ 를 추가하는 것이 낫다

12년 7월 22일 일요일

Page 10: Clean code Chapter.2

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

• 기억력을 믿고, 의미 없는 이름을 사용하지 마라

• 코드를 읽으면서 변수 이름을 자신이 아는 이름으로 변환해야 한다면 그 이름은 바람직하지 못한 것이다

• 문제 영역이나 해법 영역에서 사용하지 않는 이름을 선택했기 때문

12년 7월 22일 일요일

Page 11: Clean code Chapter.2

클래스 이름

• 클래스 이름과 객체 이름은 명사나 명사구가 적합

• Customer, WikiPage, Account, AddressParser

• 불용어는 피해라

• Manager, Processor, Data, Info...

12년 7월 22일 일요일

Page 12: Clean code Chapter.2

메소드 이름

• 메소드 이름은 동사나 동사구가 적합

• ex) postPayment, deletePage, save ...

• 접근자, 변경자, 조건자는 자바 빈 표준에 따른 표기법 사용

• get, set, is

• 생성자를 중복해 정의할 때는 정적 팩토리 메소드를 사용

생성자 정적 팩토리 메소드

Complex fulcrmPoint = new Complex(23.0); Complex fulcrmPoint = Complex.FromReadlNumber(23.0);

12년 7월 22일 일요일

Page 13: Clean code Chapter.2

기발한 이름은 피하라

• 이름이 너무 기발하면 저자와 생각이 비슷한 사람만 이름을 기억한다

• 재미난 이름보다 명확한 이름을 선택

12년 7월 22일 일요일

Page 14: Clean code Chapter.2

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

• 추상적인 개념 하나에 단어 하나를 선택

• ex) fetch, retrieve, get을 제각각 사용할 경우 혼란이 초래

• 일관성 있는 어휘를 사용해라

12년 7월 22일 일요일

Page 15: Clean code Chapter.2

말장난을 하지 마라

• 한 단어를 두 가지 목적으로 사용하지 마라

• Ex) 기존 값 두개를 더하거나 이어서 새로운 값을 만드는 메소드 add가 있을 경우

• 집합에 값 하나를 추가하는 메소드는 무엇으로 해야할까?

• add 보다 insert나 append가 적당

12년 7월 22일 일요일

Page 16: Clean code Chapter.2

해법 영역에서 사용하는 이름을 사용하라

• 기술적인 개념에는 기술적인 이름이 적합

• 코드를 읽는 사람은 프로그래머

• 문제 영역에서 모든 이름을 가져 올 경우 같은 기존 개념과 충돌이 있을 수 있음

• EX) AccountVisitor, JobQueue ...

12년 7월 22일 일요일

Page 17: Clean code Chapter.2

문제 영역과 관련 있는 이름을 사용하라

• 적절한 ‘프로그래머 용어’가 없을 경우 문제 영역 내의 이름을 사용

• 유지 보수시 업무 전문가를 통해 의미 파악 가능

• 문제 영역 개념과 관련 깊은 코드라면 문제 영역의 이름을 사용

12년 7월 22일 일요일

Page 18: Clean code Chapter.2

의미 있는 맥락을 추가하라

• 대다수 이름은 스스로 의미가 분명하지 않다

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

• 모든 방법이 실패하면, 접두어를 사용해라

• Ex) firstName, lastName, street, houseNumber, city, state, zipcode

• 전체적으로 보면 주소를 표현 한 것을 알 수 있지만, 각각을 보았을 때는 의미가 모호

• addr 접두어 추가

• addrFirstName, addrLastName, addrStreet, addrHouseNumber ...

• But, Address 클래스를 생성하고, 그 속성으로 사용하는 것이 더 효과적

12년 7월 22일 일요일

Page 19: Clean code Chapter.2

의미 있는 맥락을 추가하라 - 예제맥락이 불분명한 변수 클래스를 사용하여 맥락을 분명하게 한 변수

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); }

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

12년 7월 22일 일요일

Page 20: Clean code Chapter.2

불필요한 맥락을 없애라

• 의미가 분명한 경우에 짧은 이름이 긴 이름보다 낫다

• Ex) 고급 휘발유 충전소(Gas Station Deluxe) 시스템 내의 클래스 이름

• 모든 클래스의 접두어로 GSD를 사용하는 것은 바람직하지 못함

12년 7월 22일 일요일

Page 21: Clean code Chapter.2

마치면서

• 좋은 이름을 선택하려면?

• 설명하는 능력이 뛰어나야 한다

• 문화적 배경이 같아야 한다

• 좋은 이름은 가독성을 높인다

• 자신의 기억력에 의존하기 보다는 명확하고 읽기 쉬운 이름을 사용해라

12년 7월 22일 일요일