Hayden's Archive
클린코드(Clean Code) 1, 2장 - 로버트 C. 마틴 본문
book.naver.com/bookdb/book_detail.nhn?bid=7390287
1. 깨끗한 코드
- 궁극적으로 코드는 요구사항을 표현하는 언어
- 나쁜 코드가 쌓일수록 팀 생산성은 떨어진다
- 시간을 들여 깨끗한 코드를 만드는 노력 = 비용을 절감하는 방법 + 전문가로서 살아남는 길
- 기한을 맞추는, 빨리 가는 유일한 방법은 언제나 코드를 최대한 깨끗하게 유지하는 습관
- 코드를 읽는 시간 대 코드를 짜는 시간 비율이 10대 1을 훌쩍 넘는다. 새 코드를 짜면서 우리는 끊임없이 기존 코드를 읽는다. 기존 코드를 읽어야 새 코드를 짜므로 읽기 쉽게 만들면 사실은 짜기도 쉬워진다.
- 코드를 잘 짜는 것에서 그치지 않고 시간이 지나도 언제나 깨끗하게 유지해야 한다. 시간이 지날수록 점점 코드가 좋아지도록 한다.
- ex) 변수 이름 하나 개선 / 조금 긴 함수 하나를 분할 / 약간의 중복 제거 / 복잡한 if문 하나를 정리
2. 의미 있는 이름
- 이름을 잘 짓는 간단한 규칙
- 의도를 분명히 밝혀라
- 의도가 분명한 이름이 정말로 중요하다. 이름을 주의 깊게 살펴서 더 나은 이름이 떠오르면 개선하자.
- 변수(또는 함수나 클래스)의 존재 이유/수행 기능/사용 방법을 드러낼 수 있도록 이름을 짓는다.
- 따로 주석이 필요하다면 의도를 분명히 드러내지 못했다는 말
- 코드의 함축성(코드의 맥락)이 명시적으로 드러나야 한다.
- 그릇된 정보를 피하라
- 코드에 그릇된 단서를 남겨서는 안 된다. 코드의 의미를 흐릴 수 있기 때문이다.
- 약어 사용에 유의한다
- 실제 List가 아니라면 List라 명명하지 않는다. 실제 컨테이너가 List인 경우라도 컨테이너 유형을 이름에 넣지 않는 편이 바람직하다. (accountLIst -> 실제 List가 아니라면, accountGroup, bunchOfAccounts, Accounts로 명명함)
- 서로 흡사한 이름을 사용하지 않도록 주의한다. ex) XYZControllerForEfficientHandlingOfStrings와 XYZControllerForEfficientStorageOfStrings
- 유사한 개념은 유사한 표기법 사용(정보) / 일관성이 떨어지는 표기법(그릇된 정보)
- 의미 있게 구분하라
- 저자의 의도가 드러나도록 의미 있게 구분한다.
- 연속적인 숫자를 덧붙인 이름(a1, a2, ..)은 의도적인 이름과 정반대다
- 불용어를 추가한 이름도 아무런 정보를 제공하지 않고 구분이 되지 않는다 ex) Product와 ProductInfo / money와 moneyAmount
- a나 the와 같은 접두어는 사용하지 않는다
- 변수 이름에 variable이라는 단어, 표 이름에 table이라는 단어 금물
- 발음하기 쉬운 이름을 사용하라
- 검색하기 쉬운 이름을 사용하라
- 이러한 관점에서는 긴 이름이 짧은 이름보다 검색하기에 좋다.
- 검색하기 쉬운 이름이 상수보다 좋다
- 상수 5만 쓰면 5가 들어가는 이름이 다 검색되지만, WORK_DAYS_PER_WEEK로 쓰면 찾기 편하다
- 인코딩을 피하라
- 굳이 부담을 더하지 않아도 이름에 인코딩할 정보는 아주 많음
- 유형이나 범위 정보까지 인코딩에 넣으면 그만큼 이름을 해독하기 어려워짐
- 헝가리식 표기법
- 프로그래밍 언어에서 변수 및 함수의 인자 이름 앞에 데이터 타입을 명시하는 코딩 규칙
- 요즘 나오는 프로그래밍 언어는 훨씬 많은 타입을 지원하며, 컴파일러가 타입을 기억하고 강제함
- 변수 이름에 타입을 인코딩할 필요가 없음
- 객체는 강한 타입(Strongly_Typed)이며, IDE는 컴파일하지 않고도 타입 오류 감지 가능
- 멤버 변수 접두어
- 멤버 변수에 m_이라는 접두어를 붙이지 않음
- 클래스와 함수는 접두어가 필요없을 정도로 작아야 마땅함
- 인터페이스 클래스(Interface Class)와 구현 클래스(Concrete Class)
- 인터페이스 이름은 접두어를 붙이지 않는 편이 좋음
- 접두어 I는 주의를 흐트리고 과도한 정보를 제공함
- 인터페이스 클래스 이름과 구현 클래스 이름 중 하나를 인코딩해야 한다면 구현 클래스 이름을 택하는 게 나음
- ShapeFactoryImpl나 심지어 CShapeFactory가 IShapeFactory보다 좋음
- 인터페이스 이름은 접두어를 붙이지 않는 편이 좋음
- 굳이 부담을 더하지 않아도 이름에 인코딩할 정보는 아주 많음
- 자신의 기억력을 자랑하지 마라
- 독자가 코드를 읽으면서 변수 이름을 자신이 아는 이름으로 변환해야 하는 일이 없어야 함
- 일반적으로 문제 영역이나 해법 영역에서 사용하지 않는 이름을 선택했기 때문임
- 문자 하나만 사용하는 변수 이름은 문제가 있음
- 루프 범위가 아주 작고 다른 이름과 충돌하지 않을 때, 루프에서 반복 회수를 세는 i, j, k는 괜찮음(l은 절대 안 됨)
- 똑똑한 프로그래머 : 자신의 정신적 능력을 과시
- 전문가 프로그래머 : 명료함이 최고라는 사실 이해. 자신의 능력을 좋은 방향으로 사용하여 남들이 이해하는 코드를 내놓음
- 독자가 코드를 읽으면서 변수 이름을 자신이 아는 이름으로 변환해야 하는 일이 없어야 함
- 클래스 이름
- 클래스 이름과 객체 이름은 명사나 명사구가 적합함. 동사는 사용하지 않음
- 좋은 예
- Customer, WikiPage, Account, AddressParser 등
- 피해야 할 단어
- Manager, Processor, Data, Info 등
- 메서드 이름
- 동사나 동사구가 적합함
- 좋은 예
- postPayment, deletePage, save 등
- 접근자(Accessor), 변경자(Mutator), 조건자(Predicate)는 JavaBean 표준에 따라 get, set, is를 붙임
- 생성자(Constructor)를 중복정의(Overload)할 때는 정적 팩토리 메서드를 사용함. 메서드는 인수를 설명하는 이름 사용.
- Complex fulcrumPoint = Complex.FromRealNumber(23.0);
- Complex fulcrumPoint = new Complex(23.0); 보다 위의 코드가 더 좋음
- 생성자 사용을 제한하려면 해당 생성자를 private로 선언
- 기발한 이름은 피하라
- 재미있는 이름보다 명료한 이름 사용
- 특정 문화에서만 사용하는 농담을 피함. 의도를 분명하고 솔직하게 표현.
- 한 개념에 한 단어를 사용하라
- 추상적인 개념 하나에 단어 하나를 선택해서 이를 고수함. 일관성 있는 어휘 사용.
- 똑같은 메서드를 클래스마다 fetch, retrive, get으로 제각각 부르면 혼란스러움
- 동일 코드 기반에 controller, manager, driver를 섞어 쓰면 혼란스러움
- 이름이 다르면 독자는 당연히 클래스도 다르고 타입도 다르리라 생각함
- 메서드 이름은 독자적이고 일관적이어야 함(주석을 뒤져보지 않고도 프로그래머가 올바른 메서드를 선택할 수 있도록)
- 추상적인 개념 하나에 단어 하나를 선택해서 이를 고수함. 일관성 있는 어휘 사용.
- 말장난을 하지 마라
- 한 단어를 두 가지 목적으로 사용하지 말 것. 다른 개념에 같은 단어 사용 = 말장난.
- 같은 맥락이 아닌데도 '일관성'을 고려해서 add라는 단어를 선택한 경우
- 지금까지 구현한 add 메서드는 모두가 기존 값 두 개를 더하거나 이어서 새로운 값을 만든다고 가정
- 새로 작성하는 메서드는 집합에 값 하나를 추가해야 함
- 이럴 경우 새로 작성하는 메서드는 기존 add 메서드와 맥락이 다르므로, insert나 append라는 이름이 적당함
- 해법 영역에서 가져온 이름을 사용하라
- 코드를 읽을 사람도 프로그래머이므로 전산 용어, 알고리즘 이름, 패턴 이름, 수학 용어 등을 사용해도 됨
- 하지만 모든 이름을 문제 영역(domain)에서 가져오는 정책은 현명하지 않음
- 같은 개념을 다른 이름으로 이해하던 동료들이 매번 고객에게 의미를 물어야 함
- 프로그래머에게 익숙한 개념에는 기술 이름이 가장 적합한 선택
- VISITOR 패턴에 익숙한 프로그래머는 AccountVisitor라는 이름을 금방 이해함
- JobQueue를 모르는 프로그래머는 없을 것
- 문제 영역에서 가져온 이름을 사용하라
- 적절한 '프로그래머 용어'가 없을 경우 문제 영역(domain)에서 이름을 가져옴
- 코드를 보수하는 프로그래머가 분야 전문가에게 의미를 물어 파악 가능
- 문제 영역 개념과 관련이 깊은 코드라면 문제 영역에서 이름을 가져와야 함
- 적절한 '프로그래머 용어'가 없을 경우 문제 영역(domain)에서 이름을 가져옴
- 의미 있는 맥락을 추가하라
- 클래스, 함수, 이름 공간에 분명한 의미를 넣어 맥락을 부여함
- firstName, lastName, street, houseNumber, city, state, zipcode라는 변수가 있을 때, 변수를 훑어보면 주소라는 사실을 금방 알아챔. 하지만 어느 메서드가 state라는 변수 하나만 사용할 경우, 변수 state가 주소 일부라는 사실을 금방 알아챌 수 없음
- add라는 접두어를 추가해 addFirstName, addLastName, addState라 쓰면 맥락이 좀 더 분명해짐. 변수가 좀 더 큰 구조에 속한다는 사실이 적어도 독자에게는 분명해지는 것
- 물론 Address라는 클래스를 생성하는 것이 더 좋음
- 이러면 변수가 좀 더 큰 개념에 속한다는 사실이 컴파일러에게도 분명해짐
- 불필요한 맥락을 없애라
- 고급 휘발유 충전소(Gas Station Deluxe)라는 애플리케이션을 짤 때, 모든 클래스 이름을 GSD로 시작하면 안 됨
- IDE에서 지원하는 자동 완성 키를 제대로 활용할 수 없음
- 일반적으로는 의미가 분명할 경우, 짧은 이름이 긴 이름보다 좋음.
- 이름에 불필요한 맥락을 추가하지 않도록 주의함
- accountAddress나 customerAddress는 Address 클래스 인스턴스로는 좋은 이름이나 클래스 이름으로는 적합하지 않음
- Address는 클래스 이름으로 적합함
- 포트 주소, MAC 주소, 웹 주소를 구분해야 한다면, 의미를 좀 더 분명히 하기 위해 PostalAddress, MAC, URI라는 이름도 괜찮음
- 고급 휘발유 충전소(Gas Station Deluxe)라는 애플리케이션을 짤 때, 모든 클래스 이름을 GSD로 시작하면 안 됨
- 의도를 분명히 밝혀라
- 마치면서
- 좋은 이름을 선택하는 능력
- 설명 능력이 뛰어나야 하고 문화적인 배경이 같아야 함
- 기술, 비즈니스, 관리 문제가 아니라 교육 문제
- 좋은 이름을 선택하는 능력