2022.02.20
2장. 의미있는 이름
변수나 함수 그리고 클래스 이름은 다음과 같은 굵직한 질문에 모두 답해야 한다. 변수(혹은 함수나 클래스)의 존재 이유는? 수행 기능은? 사용 방법은? 따로 주석이 필요하다면 의도를 분명히 드러내지 못했다는 말이다.
여러 계정을 그룹으로 묶을 때, 실제 List가 아니라면 accountList라 명명하지 않는다. 프로그래머에게 List라는 단어는 특수한 의미다. 계정을 담는 컨테이너가 실제 List가 아니라면 프로그래머에게 그릇된 정보를 제공하는 셈이다. 그러므로 accountGroup, bunchOfAccounts, 아니면 단순히 Accounts라 명명한다.
서로 흡사한 이름을 사용하지 않도록 주의한다.
유사한 개념은 유사한 표기법을 사용한다. 이것도 정보다. 일관성이 떨어지는 표기법은 그릇된 정보다. 이름으로 그릇된 정보를 제공하는 진짜 끔찍한 예가 소문자 L이나 대문자 O 변수다. 소문자 L은 숫자 1처럼 보이고 대문자 O는 숫자 0처럼 보인다.
명확한 관례가 없다면 money는 moneyAmount와 구분이 안 된다. customerInfo는 customer와, accountData는 account와, theMessage는 message와 구분이 안 된다. 읽는 사람이 차이를 알도록 이름을 지어라.
발음하기 어려운 이름은 토론하기도 어렵다. 바보처럼 들리기 십상이다. "흠, 여기 비 씨 알 3 씨 엔 티에 피 에스 지 큐 int가 있군요. 보입니까?" 발음하기 쉬운 이름은 중요하다. 프로그래밍은 사회 활동이기 때문이다.
MAX_CLASSES_PER_STUDENT는 grep으로 찾기가 쉽지만, 숫자 7은 은근히 까다롭다. 7이 들어가는 파일 이름이나 수식이 모두 검색되기 때문이다.
개인적으론는 간단한 메서드에서 로컬 변수만 한 문자를 사용한다. 이름 길이는 범위 크기에 비례해야 한다.
클래스 이름과 객체 이름은 명사나 명사구가 적합하다. Customer, WikiPage, Account, AddressParser 등이 좋은 예다. Manager, Processor, Data, Info 등과 같은 단어는 피하고, 동사는 사용하지 않는다.
메서드 이름은 동사나 동사구가 적합하다. postPayment, deletePage, save 등이 좋은 예다. 접근자(Accessor), 변경자(Mutator), 조건자(Predicate)는 javabean 표준에 따라 값 앞에 get, set, is를 붙인다.
생성자(Constructor)를 중복정의(overload)할 때는 정적 팩토리 메서드를 사용한다. 메서드는 인수를 설명하는 이름을 사용한다. 생성자 사용을 제한하려면 해당 생성자를 private로 선언한다.
추상적인 개념 하나에 단어 하나를 선택해 이를 고수한다. 예를 들어, 똑같은 메서드를 클래스마다 fetch, retrieve, get으로 제각각 부르면 혼란스럽다. 어느 클래스에서 어느 이름을 썼는지 기억하기 어렵다.
스스로 의미가 분명한 이름이 없지 않다. 하지만 대다수 이름은 그렇지 못하다. 그래서 클래스, 함수, 이름 공간에 넣어 맥락을 부여한다. 모든 방법이 실패하면 마지막 수단으로 접두어를 붙인다.
일반적으로는 짧은 이름이 긴 이름보다 좋다. 단, 의미가 분명한 경우에 한해서다. 이름에 불필요한 맥락을 추가하지 않도록 주의한다.
accountAddress와 customerAddress는 Address 클래스 인스턴스로는 좋은 이름이나 클래스 이름으로는 적합하지 못하다. Address는 클래스 이름으로 적합하다. 포트 주소, MAC 주소, 웹 주소를 구분해야 한다면 PostalAddress, MAC, URI라는 이름도 괜찮겠다. 그러면 의미가 좀 더 분명해진다.
"발음하기 쉬운 이름을 사용하라" 부분은 생각도 못해봤던 문제였다.
이름을 짓는 일은 늘 어렵다. 좀 더 효율적인 코드가 될 수 있는 이름을 사용할 수 있도록 앞으로 고민해봐야겠다.
class SalesWorker:
def __init__(self, name)
self.name = name
def work(self):
print(self.name, 'sells something')
class DevWorker:
def __init__(self, name):
self.name = name
def work(self):
print(self.name, 'develops something')
worker1 = SalesWorker('Dave')
worker2 = SalesWorker('David')
worker3 = SalesWorker('Andy')
worker4 = DevWorker('Aiden')
worker5 = DevWorker('Tina')
worker6 = DevWorker('Anthony')
workers = [worker1, worker2, worker3, worker4, worker5, worker6]
#객체 타입에 따라 코드는 동일하나, 실제 호출되는 work 메서드가 다름
for worker in workers:
worker.work()
[output]
Dave sells something
David sells something
Andy sells something
Aiden develops something
Tina develops something
Anthony develops something
불용어(noise word)란 분석에 큰 의미가 없는 단어를 지칭한다. 예를 들어 the, a, an, is, my 등과 같이 문장을 구성하는 필수 요소지만 문맥적으로 큰 의미가 없는 단어가 이에 속한다.
JAVA에서 사용하는 용어인 듯 하다.
구상(또는 구체)클래스(Concrete class)
추상화
자바에서는 인터페이스(Interface)와 추상클래스(Abstract class)가 추상화의 특징을 표현한다. 이 특징은 중복코드, 클래스를 그룹화시키는 등의 역할을 하게 되면서 실세계를 객체로 보는 객체의 관계를 계층적으로 표현한다.
인터페이스는 메소드의 시그니처만을 표현하며 구현체는 존재하지 않는다.
추상화클래스(Abstract class)는 구현체가 존재하지만 모든 메소드가 구현되지 않으며 추상화메소드를 포함하고 있다. (불완전한 클래스)
정적 팩토리 메서드란 객체 생성의 역할을 하는 클래스 메서드라는 의미로 요약해볼 수 있다.
Visitor Pattern(방문자 패턴): 알고리즘을 객체 구조에서 분리시키는 디자인 패턴이다.
분리를 하게 되면, 구조를 수정하지 않고 새로운 동작을 기존 객체에 추가할 수 있다.