서론 [Clean Code 책 소개]
IT 개발자들에게 거의 필수 교과서라고 할 수 있는 책이다.
코딩에 관심 좀 있다하면 다들 한 권씩은 소장하고 있는 것 같다. 거의 바이블인듯 (아닐 수도 있음 ㅎ)
나도 그 중에 한명이 되어보고자 책을 구매했지만 바로 초심 잃고 이제서야 읽기 시작함 ㅎㅎ
이 책을 공부하면서 얻은 중요한 것들과 내 생각을 정리해보고자 한다.
1장. 깨끗한 코드
협업을 하면서 다른 사람이 쓴 코드를 보면, 간혹 이게 뭔말인가 싶은 코드들이 있다. 또는 '굳이...? 이렇게...?' 라는 생각이 들 때가 있을 것이다. 물론 나도 예외는 아니다. 지금도 흑역사로 남은 코드들을 들킬 때면 머쓱머쓱 해진다.
나쁜 코드
귀찮아서, 혹은 지금 당장 돌아가기만 하면 되니까 라는 마음으로 코드를 짜게 된다면 훗날 그로 인한 대가를 무조건 치른다.
우선 나쁜 코드가 쌓일 수록 팀 생산성이 떨어진다. 그 코드를 혼자만 볼 것이라고 생각하지 마라.
프로젝트 진도가 안 나가거나 인수인계가 힘들 수 있다. 유지보수도 굉장히 힘들다. 코드를 보완하기 위해서 우선 그 코드를 분석해야 하는데 그 단계가 너무 오래 걸림;
어느 정도 연차가 되면 나쁜 코드라는 것을 구분할 줄 아는 단계가 된다. 그렇다고 깨끗한 코드를 잘 작성할 줄 안다는 뜻이 아니며 더 나은 개발자가 되기 위하여 우리는 '코드 감각'을 키워 '깨끗한 코드' 를 유지할 필요가 있다.
깨끗한 코드
책에서 나온 유명 프로그래머들의 정의를 몇가지 정리해보자면
- 효율성 - 한 가지 일을 제대로 집중하며 의존성을 최대한 줄여야 한다.
- 가독성 - 의도를 숨기지 않는다.
- 다른 사람이 고치기 쉬워야 한다.
- 주의를 기울인 코드다.
- 표현력 - 중복이 없는 의미 있는 이름을 포함한다.
다음은 책 안에서 내가 제일 공감하는 말이다.
코드를 독해하느라 머리를 쥐어짤 필요가 없어야 한다. 읽으면서 짐작한 대로 돌아가는 코드가 깨끗한 코드다.
(이유는 지금 머리 쥐어짜고 있기 때문...)
새 코드를 짜면서 우리는 끊임없이 기존 코드를 읽는다. ... 비록 읽기 쉬운 코드를 짜기 쉽지 않더라도 읽기 쉬운 코드는 중요하다. 하지만 기존 코드를 읽어야 새 코드를 짜므로 읽기 쉽게 만들면 사실은 짜기도 쉬워진다.
2장. 의미 있는 이름
1) 의도를 분명하게 밝히기
- 변수, 함수 또는 클래스의 존재 이유, 수행 기능, 사용 방법이 드러나야 한다.
- 의도를 설명해야 하는 주석이 없어야 한다.
int d; // 경과시간(단위: 날짜) -- (1)
int elapsedTimeInDays;
int daysSinceCreation; // -- (2)
- (1)은 아무 의미가 드러나지 않는다. 주석이 없으면 날짜라는 느낌이 전혀 들지 않는다.
- (1)에 비해 (2)는 측정하려는 값과 단위 표현이 명확하다.
public List<int[]> getThem() {
List<int[]> list1 = new ArrayList<int[]>();
for (int[] x : theList)
if (x[0] == 4)
list1.add(x);
return list1;
}
위 코드만 봐서는 아래와 같은 코드 맥락을 전혀 알 수 없다.
- theList에 무엇이 들었는가?
- theList에서 0번째 값이 어째서 중요한가?
- 값 4가 무슨 의미인가?
- 함수가 반환하는 리스트 list1을 어떻게 사용하는가?
public List<Cell> getFlaggedCells() {
List<Cell> flaggedCells = new ArrayList<Cell>();
for (Cell cell : gameBoard)
if (cell[STATUS_VALUE] == FLAGGED)
flaggedCells.add(cell);
return flaggedCells;
}
이름을 바꿔주는 것만으로도 1~4를 유추할 수 있어 함수를 이해하기 쉬워졌다.
2) 그릇된 정보 피하기
- 이미 널리 쓰이는 의미를 굳이 다른 의미로 바꿔서 사용하지 않는다.
- 리스트나 그룹이 아닌 데이터를 *List 또는 *Group으로 명명하지 않는다.
- 흡사한 이름 사용에 유의한다.
- 유사한 개념은 유사한 표기법을 사용한다. (코드 자동 완성 기능의 핫키 후보 목록을 적극 활용한다.)
string userList = '계정'; // (x) 그룹 또는 리스트가 아님
string user = '계정'; // 실제로 List가 아니라면 그릇된 정보를 제공하는 셈이므로 'List'제외
int a = l;
if (O == l) a = 1;
// 소문자 l과 대문자 O 사용은 혼란을 야기한다. 저게 1이야 0이야
3) 의미있게 구분하기
- 이름이 다르면 의미도 달라져야 한다.
- 연속된 숫자를 덧붙이는 방식은 적절하지 못하다. ( a1, ..., aN)
- 불용어(Info, Data, Object 등 애매한 단어)를 추가하는 방식도 적절하지 못하다.
//각각이 무슨 함수인지 구분 불가
getActiveAccount();
getActiveAccounts();
getActiveAccountInfo();
4) 발음하기 쉬운 이름 사용
class 퀢스턺어 { // -- (1)
private Date genymdhms;
private String 눼예룲 = '히히';
}
class Customer { // -- (2)
private Date generationTimestamp;
private String 내이름 = '히히';
}
(관종이 아닌 이상 (1)번처럼 지을 일 없겠지만) 누가 봐도 (2)번이 발음하기 쉽고 지적인 대화가 가능해진다. (1)은 남들 앞에서 발음했다간 좀 부족해보일수도..
5) 검색하기 쉬운 이름 사용
- 이름 길이는 사용하는 범위 크기에 비례해야 한다.
- 숫자 보다는 검색하기 쉬운 이름을 사용한다.
- 문자 하나만 사용하고 싶다면 간단한 메서드에서의 로컬 변수 정도만 한 문자를 사용한다.
6) 인코딩 피하기
- 이제는 헝가리식 표기법(이름 앞에 데이터 타입을 명시)을 피한다.
- 멤버 변수 접두어는 붙일 필요 없다. (m_* )
7) 기억하기 쉬운 이름 사용
- 나를 믿지 말고 다른 사람도 믿지 말자
8) 한 개념에 한 단어 사용
- 추상적인 개념 하나에 단어 하나를 선택해서 유지한다.
같은 역할을 하는 메서드를 클래스마다 다르게 짓지 않는다. (한번 *Manager라고 썼으면 책임지세여) - IDE 내 코드 자동완성 활용한다.
9) 역할에 맞는 적합한 이름
- 클래스와 객체 이름은 명사나 명사구가 적합하다.
- 메서드 이름은 동사나 동사구가 적합하다. (post~, delete~, is~ 등)
class Customer { ... }
//class CustomrerInfo { ... } -- Info 같이 쓸데없는 단어 쓰지 말기
string name = user.getName(); //javabean 표준을 따르기
user.setName("hee");
if(paycheck.isPosted()) ...
10) 의미있는 맥락
- ex. street, city, state, zipcode는 같이 있으면 주소 변수라는 것을 알지만 state 하나만 사용하는 메서드가 있다면? 알아채기 힘듦
=> 이럴 때는 addr라는 접두어를 추가해 (addrState) 맥락을 분명하게 할 수 있다. - 불필요한 맥락을 없앤다. 의미가 분명한 경우에 짧은 이름이 긴 이름보다 좋다.