클린 코드 책을 읽고 정리한 내용입니다.
1. 의도를 분명히 밝혀라
좋은 이름을 지으려면 시간이 걸리지만 좋은 이름으로 절약하는 시간이 훨씬 많아집니다.
존재 이유, 수행 기능, 사용 방법이 잘 드러나도록 지어야 합니다.
예시1
1 2 3 4 5 6 7 8
// Bad int d; // elapsed time in days // Good int elapsedTimeInDays; int daysSinceCreation; int daysSinceModification; int fileAgeInDays;
예시2
1 2 3 4 5 6 7 8 9
// Bad 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을 어떻게 사용하는가?
다음과 같이 수정해본다면?
1 2 3 4 5 6 7 8 9
// Good public List<int[]> getFlaggedCells(){ List<int[]> flaggedCells = new ArrayList<int[]>(); for(int[] cell: gameBoard) if(cell[STATUS_VALUE] == FLAGGED) flaggedCells.add(cell); return flaggedCells; }
- 리스트 gameBoard는 말그대로 게임보드구나
- gameBoard의 0번째 값은 상태를 뜻하는구나
- 값 4는 깃발이 꽂힌 상태를 뜻하는구나
- 깃발이 꽂힌 상태의 게임보드를 찾아내려고 하는구나
코드의 단순성은 변하지 않으면서 함축성이 좋아집니다.
한층 더 수정?
1 2 3 4 5 6 7 8
public List<Cell> getFlaggedCells(){ List<Cell> flaggedCells = new ArrayList<Cell>(); for (Cell cell: gameBoard) if (cell.isFlagged()) flaggedCells.add(cell); return flaggedCells; }
2. 그릇된 정보를 피하라
널리 쓰이는 의미가 있는 단어를 다른 의미로 사용하지 말아야 합니다.
- ex) 직각삼각형의 빗변(hypotenuse)을 구현할 때는 hp가 훌륭한 약어로 보일지라도 hp는 유닉스 플랫폼을 가르키는 이름이라 혼란을 가중시킵니다.
사용하는 타입에 맞게 이름 지정합니다.
ex) 사용자의 계정 정보를 그룹핑하는 변수가 리스트 타입이 아닌데 accountList라고 지정 시 그릇된 정보 제공합니다.
1 2 3 4 5 6
fun findAllById(pageable: Pageable): Page<String> Page: pageSize 30 val customInfoList = findAllById(....) // 4 customInfoList.size = 4 , 30 customInfoPage.numberOfElement = 4
서로 흡사한 이름 사용하지 말아야 합니다.
유사한 개념은 유사한 표기법을 사용 하여 일관성이 떨어지지 않도록 해야 합니다.
3. 의미 있게 구분하라
- 연속적인 숫자나 의미가 불분명한 불용어(noise word)를 추가하는 방식으로 이름을 구분하지 말 것
- 이름이 달라지면 의미도 달라져야 함
- 불용어 예시) info, data, variable, table, string, …
같은 이름이 이미 존재한다는 이유로 Product, ProductInfo, ProductData 이런식으로 이름 짓지 말 것
1 2 3
val accountIdForUserNo: List<Account> = findAllByUserNo(userNo..) val accountIdForAccountNumber: List<Account> = findAllByAccountNumber(..)
4. 발음하기 쉬운 이름을 사용하라
5. 검색하기 쉬운 이름을 사용하라
문자 하나를 사용하는 이름과 상수는 텍스트 코드 내에서 쉽게 눈에 띄지 않습니다.
ex) 한 학생 당 수강할 수 있는 클래스가 7개라면, 7이라는 숫자를 MAX_CLASSES_PER_STUDENT라는 상수로 선언해놓고 쓰는게 바람직합니다.
왜? MAX_CLASSES_PER_STUDENT는 grep으로 찾기 쉽지만, 숫자 7은 7이 들어가는 파일 이름이나 수식이 모두 검색되어 까다롭습니다.
이름 길이는 범위 크기에 비례해야 합니다.
- 여러 곳에서 사용될 수록 검색하기 쉬운 이름이 바람직합니다.
- 간단한 메서드에서 로컬 변수정도는 한 문자를 사용해도 괜찮습니다.
6. 인코딩을 피하라
인코딩은 개발자에게 불필요한 정신적 부담입니다.
이름에 불필요한 정보를 추가하기 보다 IDE를 활용해야 합니다.
헝가리식 표기법
멤버 변수 접두어
- 멤버변수에 m_이라는 접두어 붙일 필요 하지 않습니다.
- 멤버 변수를 따로 표시해주는 IDE를 사용합니다.
인터페이스 클래스와 구현 클래스
- 인터페이스 클래스 이름과 구현 클래스 중 하나를 인코딩해야 한다면 구현 클래스를 인코딩 하는 것을 추천합니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14
interface CustomerInfoCheckService{ fun checkPhoneNumberValidation(phoneNumber: String): Boolean fun checkNameValidation(name: String): Boolean } class CustomerInfoCheckServiceImpl(): CustomerInfoCheckService{ override fun checkPhoneNumberValidation(phoneNumber: String): Boolean { ... } override fun checkNameValidation(name: String): Boolean { ... } }
7. 자신의 기억력을 자랑하지 마라
- 코드를 읽으면서 독자가 자신이 아는 이름으로 변환해야 한다면 바람직하지 못한 이름입니다.
- 문자 하나만 사용하는 변수 이름은 문제가 있습니다.
- 루프에서 반복 횟수 세는 변수 제외 (i,, j, k) → 소문자 l 는 안됩니다.
- 단, 루프 범위가 아주 작고 다른 이름과 충돌하지 않을 때만 사용 가능합니다.
- 루프에서 반복 횟수 세는 변수 제외 (i,, j, k) → 소문자 l 는 안됩니다.
8. 클래스 이름
- 클래스/객체 이름은 명사나 명사구를 사용 합니다.
- 동사는 사용 하지 않습니다.
- Manager, Processor, Data, Info 등의 이름은 피합니다.
9. 메서드 이름
메서드 이름은 동사나 동사구가 적합합니다.
접근자, 변경자, 조건자는 javabean 표준에 따라 get, set, is 붙입니다.
생성자를 overload할 때는 정적 팩토리 메서드 사용 합니다.
1 2 3 4
// 첫번째 보다 두 번째 방법이 더 좋다. Complex fulcrumPoint = new Complex(23.0); Complex fulcrumPoint = Complex.FromRealNumber(23.0);
10. 기발한 이름은 피하라
- 재미난 이름보다 명료한 이름을 선택하라
- 의도를 분명하고 솔직하게 표현하라
11. 한 개념에 한 단어를 사용하라
- 추상적인 개념 하나에 단어 하나를 선택합니다.
- ex) 똑같은 메서드를 클래스마다 fetch, retrive, get으로 제각각 부르면 혼란스럽습니다.
- 똑같은 메서드를 클래스마다 제각각 부르면 어느 클래스에서 어느 이름을 썼는지 기억하기 어렵습니다.
- 메서드 이름은 독자적이고 일관적이어야 합니다.
12. 말장난을 하지 마라
- 한 단어를 두 가지 목적으로 사용하지 말아야 합니다.
- ex)
- add 메서드 - 기존 값 두 개를 더하거나 이어서 새로운 값을 만들어야 합니다.
- 집합에 새로운 값 하나 추가하는 메서드에는? → 기존 add와 맥락이 다르니 insert나 append 사용합니다.
13. 해법 영역에서 가져온 이름을 사용하라
- 코드를 읽는 사람도 프로그래머!
- 전산 용어, 알고리즘 이름, 패턴 이름, 수학 용어 등 사용 OK
14. 문제 영역에서 가져온 이름을 사용하라
- 적절한 프로그래머 용어가 없으면 문제 영역에서 이름 가져옵니다!
15. 의미 있는 맥락을 추가하라
스스로 의미가 분명한 이름이 있으나 그렇지 못하다면 마지막 수단으로 접두어를 붙입니다!
ex) state 라는 이름의 변수가 단독으로 있으면 주소의 일부라는 사실을 알아차리기 어려우니, addrState라고, 주소를 나타내는 접두어를 붙여서 사용.
또는 상위 개념의 클래스를 생성하면 더 좋습니다.
16. 불필요한 맥락을 없애라
- 일반적으로 짧은 이름보다 긴 이름이 좋습니다.
- 단, 의미가 분명한 경우에서만!
- ex) Gas Station Deluxe라는 애플리케이션을 짠다고 가정할 때, 모든 클래스 이름을 GSD로 시작하겠다는 생각은 전혀 바람직하지 못합니다.