떼닝로그

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

개발로그/Clean Code

[2장] 의미 있는 이름

떼닝 2022. 11. 1. 18:22

의도를 분명히 밝혀라

- 좋은 이름을 지으려면 시간이 걸리지만, 좋은 이름으로 절약하는 시간이 훨씬 더 많다.

# 좋지 않은 예시
d = 0	# 경과 시간(단위: 날짜)

# 좋은 예시
elapsedTimeInDays = 0
daysSinceCreation = 0
daysSinceModification = 0
fileAgeInDays = 0

- 이름 d는 아무 의미도 드러나지 않는다. 측정하려는 값과 단위를 표현하는 이름이 필요하다.

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

def getThem() -> List(int):
	list1 = ArrayList()
	for x in theList:
		if x[0] == 4:
			list1.append(x)
	return list1

- 코드 맥락이 코드 자체에 명시적으로 드러나야 한다.

- 단순히 이름만 고쳤음에도 함수가 하는 일을 이해하기 쉬워질 수 있다. 이것이 좋은 이름이 주는 위력

그릇된 정보를 피하라

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

  ex. XYZControllerForEfficientHandlingOfStrings와 XYZControllerForEfficientStorageOfStrings... 엄청 비슷하다

- 유사한 개념은 유사한 표기법을 사용한다. 이것도 정보!...

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

- 이름으로 그릇된 정보를 제공하는 진짜 끔찍한 예가 소문자 L이나 대문자 O 변수...

의미 있게 구분하라

- 이름이 달라야 한다면 의미도 달라져야 한다.

- 연속적인 숫자를 덧붙인 이름(a1, a2, ..., aN)은 의도적인 이름과 정반대. 아무런 정보를 제공하지 못하는 이름.

- 함수 인수 이름으로 source나 destination을 사용한다면 코드 읽기가 훨씬 더 쉬워진다

- 불용어를 추가한 이름 역시 아무런 정보도 제공하지 못한다.

  Product, ProductInfo, ProductData라는 클래스가 있다면... 개념을 구분하지 않은 채 이름만 달리한 경우.

  Info나 Data는 a, an, the와 마찬가지로 의미가 불분명한 불용어

- 불용어는 중복이다. 변수 이름에 variable, 표 이름에 table이라는 단어 들어가면... 안됨

getActiveAccount()
getActiveAccounts()
getActiveAccountInfo()

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

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

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

# 1
class DtaRcrd102:
    __genymdhms = 0
    __modymdhms = 0
    __pszqint = "102"
    
# 2
class Customer:
    __generationTimestamp = 0
    __modificationTimestamp = 0
    __recordId = "102"

- genymdhms... 젠와이디에이취엠에스... 으악

- 두번째 코드를 사용하면 지적인 대화가 가능해진다.

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

- 문자 하나를 사용하는 이름과 상수는 텍스트 코드에서 쉽게 눈에 띄지 않는다

- 간단한 메서드에서 로컬 변수만 한 문자를 사용한다. 이름 길이는 범위 크기에 비례해야 한다.

# 1
for j in range(0, 34):
	s += (t[j]*4)/5

# 2
realDaysPerIdealDay = 4
WORK_DAYS_PER_WEEK = 5
sum = 0
for j in range(0, NUMBER_OF_TASKS):
	realTaskDays = taskEstimate[j] * realDaysPerIdealDay
    realTaskWeeks = (realTaskDays / WORK_DAYS_PER_WEEK)
    sum += realTaskWeeks

- 이름을 의미 있게 지으면 함수가 길어지지만, 정말정말 찾기 쉬워진다.

인코딩을 피하라

- 문제 해결에 집중하는 개발자에게 인코딩은 불필요한 정신적 부담.

헝가리식 표기법

- 헝가리식 표기법은 기존 표기법을 완전히 새로운 단계로 끌어올렸다.

- 컴파일러가 타입을 기억하고 강제한다. 클래스와 함수는 점차 작아지고 있다... -> 변수를 선언한 위치와 사용하는 위치가 멀지 않다

멤버 변수 접두어

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

- 클래스와 함수는 접두어가 필요 없을 정도로 작아야 마땅하다.

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

# 1
class Part:
	__m_dsc = 0
    def setName(name:String):
    	__m_dsc = name
        
# 2
class Part:
	self.description = ""
    def setDescription(self, description:String):
    	self.description = description

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

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

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

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

- 전문가 프로그래머는 명료함이 최고 라는 사실을 이해하고, 자신의 능력을 좋은 방향으로 사용해 남들이 이해하는 코드를 내놓는다.

클래스 이름

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

  ex. Customer, WikiPage, Account, AddressParser는 OK. Manager, Processor, Data, Info의 단어는 피하기

- 동사는 사용하지 않는다.

메서드 이름

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

  ex. postPayment, deletePage, save는 OK.

- 접근자(Accessor), 변경자(Mutator), 조건자(Predicate)는 javabean 표준에 따라 값 앞에 get, set, is를 붙인다.

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

- 생성자를 중복정의(overload) 할 때는 정적 팩토리 메서드를 사용한다. 메서드는 인수를 설명하는 이름을 사용한다.

 

# 좋음
fulcrumPoint = Complex.FromRealNumber(23.0)
# 별로
fulcrumPoint = Complex(23.0)

- 생성자 사용을 제한하려면 해당 생성자를 private으로 선언한다.

기발한 이름은 피하라

- 재미난 이름보다 명료한 이름을 선택하라

- 특정 문화에서만 사용하는 농담은 피하는 편이 좋다.

- 의도를 분명하고 솔직하게 표현하라.

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

- 추상한 개념 하나에 단어 하나를 선택해 이를 고수한다.

- 메서드 이름은 독자적이고 일관적이어야 한다. 그래야 주석을 뒤져보지 않고도 프로그래머가 올바른 메서드를 선택한다.

- 일관성 있는 어휘는 코드를 사용할 프로그래머가 반갑게 여길 선물이다.

말장난을 하지 마라

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

- 프로그래머는 코드를 최대한 이해하기 쉽게 짜야 한다.

- 집중적인 탐구가 필요한 코드가 아니라, 대충 훑어봐도 이해할 코드 작성이 목표다.

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

- 코드를 읽을 사람도 프로그래머이기 때문에 전산 요엉, 알고리즘 이름, 패턴 이름, 수학 용어 등을 사용해도 괜찮다.

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

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

- 적절한 프로그래머 용어가 없다면, 문제 영역 개념과 관련이 깊은 코드라면 문제 영역에서 이름을 가져와야 한다.

- 우수한 프로그래머와 설계자라면 해법 영역과 문제 영역을 구분할 줄 알아야 한다.

의미 있는 맥락을 추가하라

- 클래스, 함수, 이름 공간에 넣어 맥락을 부여한다. 모든 방법이 실패하면 마지막 수단으로 접두어를 붙인다.

- firstName, lastName, street, houseNumber, ... 변수를 훑어보면 주소라는 사실을 금방 알아차린다.

- addrFirstName, addrLastName, addrState라고 위의 변수들에 addr라는 접두어를 추가하면 맥락이 조금 더 분명해짐을 볼 수 있다.

- 함수 이름은 맥락 일부만 제공하며, 알고리즘이 나머지 맥락을 제공한다.

# 맥락이 불분명한 변수
def printGuessStatistics(candidate:char, count:int):
	number = ""
    verb = ""
    pluralModifier = ""
    if count == 0:
    	number = "no"
        verb = "are"
        pluralModifier = "s"
    elif count == 1:
    	number = "1"
        verb = "is"
        pluralModifier = ""
    else:
    	number = str(count)
        verb = "are"
        pluralModifier = "s"

guessMessage = print(f"There {verb}, {number}, {candidate}, {pluralModifier}")
print(guessMessage)
# 맥락이 분명한 변수
class GuessStatisticsMessage:
	def __init__(self, None):
    	__number = ""
        __verb = ""
        __pluralModifier = ""
        
    def make(self, candidate:str, count:int) -> str:
		self.createPluralDependentMessageParts(count)
        return f"There {verb}, {number}, {candidate}, {pluralModifier}"
        
    def createPluralDependentMessageParts(self, count:int):
    	if count == 0:
        	self.thereAreNoLetters()
        elif count == 1:
        	self.thereIsOneLetter()
        else:
        	self.thereAreManyLetters(count)
            
	def thereAreManyLetters(self, count:int):
		self.number = str(count)
        self.verb = "are"
        self.pluralModifier = "s"
        
    def thereIsOneLetter(self):
    	self.number = "1"
        self.verb = "is"
        self.pluralModifier = ""
        
    def thereAreNoLetters():
    	self.number = "no"
        self.verb = "are"
        self.pluralModifier = "s"

불필요한 맥락을 없애라

- 일반적으로는 짧은 이름이 긴 이름보다 좋지만, 의미가 분명한 경우에 한해서다.

- 이름에 불필요한 맥락을 추가하지 않도록 주의한다.

 

'개발로그 > Clean Code' 카테고리의 다른 글

[6장] 객체와 자료 구조  (0) 2022.12.09
[5장] 형식 맞추기  (0) 2022.12.02
[4장] 주석  (0) 2022.11.16
[3장] 함수  (0) 2022.11.02
[1장] 깨끗한 코드  (0) 2022.10.31
Comments