클린코드 책과 제로베이스 [개발자와 함께 읽는 클린코드] 강좌를 기반으로 작성하였습니다.
Chapter 1. 깨끗한 코드
클린코드 1장에서는 어떤 코드가 깨끗한 코드이며 왜 깨끗한 코드를 사용해야 하는지 설명하고 있다.
나쁜 코드
코드를 읽게 되었을 때 '뭔가 이상하다. 변수의 의미도 모르겠고 중복코드가 많네. 포맷팅도 이상하고, 함수가 너무 뚱뚱한데?'라고 느낀 다면 나쁜 코드라고 볼 수 있다.
성능이 나쁜 코드
불필요한 연산이 들어가서 개선의 여지가 있는 코드
의미가 모호한 코드
이해하기 어려운 코드, 네이밍과 그 내용이 다른 코드
중복된 코드
비슷한 내용인데 중복되는 코드들은 버그를 낳는다. (재활용이 아닌 코드를 복붙 해서 여러 군데 사용하는 경우)
나쁜 코드가 나쁜 이유
나쁜 코드는 깨진 유리창처럼 계속 나쁜 코드를 만들어지게 한다.
깨진 유리창 법칙
깨진 유리창 하나를 방치해 두면 그 지점을 중심으로 범죄가 확산되기 시작한다는 이론이며, 나쁜 코드도 마찬가지로 방치해 두면 지속적으로 확산된다.
생성성 저하
나쁜 코드는 팀 생산성을 저하시킨다. 기술부채로 쌓인 프로젝트는 수정을 더 어렵게 한다.
새로운 시스템을 만들어야 한다. (재설계의 꿈)
현 시스템을 유지보수하면서, 대체할 새로운 시스템 개발은 현실적으로 매우 어렵다.
그럼 나쁜 코드는 왜 나오는 것일까?
일정 안에 프로젝트를 완성(기능을 완성)시켜야 되지 때문이다. 하지만 역설적이게도 나쁜 코드를 프로젝트를 진행하다 보면 생산성을 저하하기 때문에 오히려 일정이 딜레이 되는 문제가 발생하게 된다.
아까도 이야기했듯이 나쁜 코드를 쌓다 보면 영향 범위(강한 연관성)가 넓어지게 되므로 지속적으로 나쁜 코드를 양산하는 방식으로 진행하게 된다. (건드렸다가 다른 부분에 영향을 미칠까 봐..)
하지만 기술부채는 부메랑처럼 우리에게 다시 돌아온다.
1장에 나온 내용들이 사실 본인이 클린코드 책을 구매해서 공부를 해야겠다고 마음을 먹게 된 이유들이다. 많은 개발자들이 이미 레거시로 된 프로젝트를 한 번쯤은 맡아서 진행해 본 경험이 있을 것이다. 본인의 경우 그런 프로젝트를 떠맡아 본 적도 있고 실제 만들어 본 경험도 있다.
정해진 일정에 맞추다 보니 기능이 동작한다. 에만 초점을 맞추어 개발하였고 끝나고 보니 엄청난 레거시 프로젝트를 진행되어 있었다. 사실 이런 프로젝트는 유지보수 및 고도화 진행하기도 어렵다. 한 곳을 고치면 다른 데가 펑펑 터지기 때문이다. 그렇다고 재설계할 수 도 없다. 회사에서는 생산성(돈이 되는 작업) 있는 업무를 지속적으로 해야 되기 때문에 개발자가 책임 없이 짠 코드를 다시 수정을 기회는 잘 오지 않는다. 그래서 애초에 나쁜 코드를 만들지 않는 습관이 중요하다.
그래서 클린코드가 머야?
우아하고 효율적인 코드는 한 가지를 제대로 한다. - 비야네 스트롭스트룹 (C++ 창시자)
단순하고 직접적이며 잘 쓴 문장처럼 읽힌다. - 그래디 부치 (OOADA 저자)
읽기 쉽고 고치기도 쉬우며 테스트 케이스가 잘 작성되어 있다. - 데이브 토마스 (OTI창립자, 이클립스 전략의 대부)
손댈 곳 없이 주의 깊게 짰다는 느낌을 준다. 고칠 궁리를 하면 계속 다시 제자리로 돌아온다. - 마이클 페더스 (WELC 저자)
많은 유명 개발자들은 클린코드를 위와 같이 정의한다.
결론적으로 클린코드란?
- 성능이 좋은 코드
- 의미가 명확한 코드( = 가독성이 좋은 코드)
- 중복이 제거된 코드
Chapter 2. 의미 있는 이름 짓기
프로젝트 안에는 수많은 요소들이 존재한다. 프로젝트명, 패키지, 클래스, 메서드, 변수 등의 이름을 우린 부여할 수 있다. 이러한 수많은 요소들의 이름을 의미를 고민하지 않고 짓는다면 나쁜 코드를 만드는 지름길로 가는 것이다.
그럼 의미있는 이름 짓는 방법은 무엇이 있을까?
의미 있는 이름 짓기
1. 의미가 분명한 이름 짓기
의미 있는 이름을 짓는 것은 생각보다 쉽지 않고 고민하는데 시간적인 소요도 발생한다. 하지만 좋은 이름을 짓게 되면 그것으로 인해 절약되는 시간은 더 클 것이다.
int a
String b
// ..
System.out.printf("User Requested %s. count = %d", b, a);
// Console 결과물
// User Requested book. count = 3
위 코드를 보고 a, b 변수가 의미하는 것을 알 수 있는가? 아래 출력문을 보고 사용자가 요청하는 것에 대한 카운터를 출력한다. 정도 유추가 가능하고 최종적으로 Console 결과물이 나와야 정확히 무엇을 의미하는지 알 수가 있다.
변수 명만으로는 기능을 유추할 수 없으니 코드를 읽는 입장에서는 매우 난감하다.
int itemCount;
String itemName;
// ..
System.out.printf("User Requested %s. Count = %d", itemName, itemCount);
// Console 결과물
// User Requested book. count = 3
a, b가 아닌 변수명의 구체적인 의미를 담아 변경하였다. 변수 명만으로 변수가 아이템에 대한 이름과 카운터를 나타내는 것을 알 수 있다. 이렇게 의미를 담으면 코드 이해와 변경이 쉬워진다.
한 번 더 나아가보자.
class SalesItem {
ItemCode code;
String name;
int count;
}
// ..
SalesItem selectedItem = salesItemRepository.getItemByCode(purchaseRequest.getItemCode());
System.out.printf("User Requested %s. Count = %d", selectedItem.getName(), selectedItem.getCount());
// Console 결과물
// User Requested book. count = 3
위에서 선언한 itemName과 itemCount를 클래스로 묶어 단순한 변수명으로 변경이 가능하다. 어차피 클래스가 해당 변수가 어떤 것에서 파생되는 지를 알려주기 때문이다.
salesItemRepository에서 getItemByCode메서드를 호출하면 해당 메서드의 명칭을 보면 Code 조건에 따라 Item을 가져오는 메서드라는 것을 알 수 있다. 파리미터로 purchaseRequest.getItemCode()를 가져오는 것도 구매요청의 Item Code를 구나라는 것을 알 수 있다.
선언된 값인 SalesItem의 이름을 selectedItem이라 명명해 해당 조건에 선택된 아이템이다라는 것을 명확히 표현한다.
결론적으로 이름만으로 실제 구현부를 보지 않아도 어떤 데이터를 가져오는 구나를 알 수가 있다.
2. 루프 속 i j k 사용하지 않기
우리는 for문을 사용할 때 i, j, k 들의 용어를 많이 사용한다.
for (int i = 0; i < message.size(); i++) {
// ..
}
for문을 사용할 때 index를 의미하는 i를 사용하지 않고 advanced for(향상된 for문)을 이용하여 처리하자.
for (String message : message) {
// ..
}
배열의 index를 사용하는 경우(몇번째 순서인지가 알아내는 것이 중요하지 않다면)가 아니라면 굳이 i, j, k라는 변수를 선언하며 사용할 필요는 없다.
자바 8 이후에는 람다가 제공되므로 람다방식을 이용하는 것도 방법 중 하나이다.
message.stream().foreach{
message -> // ..
}
만약 꼭 필요하다면 i,j,k 대신 대체할 수 있는 용어를 사용하는 것도 좋은 방법이다.
- i, j -> row, col / width, height
- i, j, k -> row, col, depth
3. 통일성 있는 단어 사용하기
Member / Customer / User
Service / Manager
Repository / Dao
사용자(유저)를 나타내는 용어를 사용하는 사람에 따라 다르게 사용한다면 그것 또한 나쁜 코드가 될 수 있다. 그 외에도 Service , Repository 클래스를 만들 경우 Manager, Dao 등과 혼용하여 사용한다면 그것 또한 혼란을 줄 수 있으므로 나쁜 코드가 된다.
이런 경우에는 팀에서 협의를 통해 공통된 용어를 정해 사용하는 것이 좋다.
4. 변수명에 타입 넣지 않기
옛날에는 헝가리식 표기법이라고 해서 컴파일러가 자료형(타입)을 인지하지 않아 변수명에 같이 넣는 방식으로 많이 사용했다고 한다. 요즘에는 컴파일러가 많이 발전되었고 특히 자바진영에서는 이러한 걱정을 굳이 할 필요가 없다.
String nameStirng -> name
Int itmePriceAmount -> itemPrice
Account[] accountArray -> accounts
List<Account> accountList -> accounts, accountList
Map<Account> accountMap
public interface IShapeFactory -> ShapeFactory
public class ShapeFactoryImpl -> ShapeFactoryImpl, CircleFactory
- nameString은 이미 String 이라는 타입을 선언하고 있기 때문에 name이라고 표기한다.
- itemPriceAmount처럼 명칭에 중복된 의미를 가지면 정리한다. (여기선 price와 amonut가 중복되었다고 봤음)
- accountArray처럼 타입명을 붙여 사용하지 말자.
- List 타입에 경우 때때로 [변수 + List] 도 사용되기도 한다.
- Map도 대체될 수 있는 단어가 마땅히 없을 경우 Map을 붙여 사용하기도 한다.
- List 나 Map도 타입 중 하나이기 때문에 팀에서 사용을 지양하라고 하면 안 쓰면 될 것 같다.
- 인터페이스의 경우 옛날에는 앞에 I를 붙여 '너 인터페이스야'라고 명시적으로 많이 사용했지만 요즘에는 사용되지는 않는다.
- 구현 클래스에 Impl 를 붙여 사용하는 경우와 구현체의 기능을 나타나는 명칭 사용하는 경우로 나눤다.
- 팀에서 정한 규칙대로 사용하자.
5. 한 개념에 한 단어를 사용하라
이 부분을 사전 정의 하지 않으면 한 개념에 대해서 다양한 용어를 사용하는 것을 많이 봤다. (본인 포함)
만약 학생을 불러오는 메서드를 만든다고 했을때 아래 예시처럼 각각 다르게 사용된다면 그것 또한 나쁜 코드가 될 수 있다. 아래 3개 어떤 거든 통일해서 쓰는 게 읽기도 편하고 통일성도 줄 수 있다.
예) getStudent, fetchStudent, retrieveStudent
6. 해법 영역에서 가져온 이름을 사용해라
코드를 읽는 사람을 대부분 이쪽 종사자이다. 그러므로 전산용어, 알고리즘 용어 등 전문적인 용어를 사용해도 된다. 프로그래머에게 친숙한 기술 용어는 사용해도 무방하다.
예) AccountVisitor, JobQueue
그럼에도 적절한 용어를 없다면 도메인(문제 영역)에서 가져온 용어의 이름을 사용한다.
예) seller, buyer
7. 의미 있는 맥락을 추가해라
이름 하나로 스스로 의미가 분명한 이름은 생각보다 많지 않을 수 있다. 그렇기 때문에 클래스, 함수, 이름 공간 등에 넣어 맥락을 부여한다.
public class Address {
private String firstName;
private String lastName;
private String street;
private String state;
private String zipCd;
private String addr1;
private String addr2;
// ..
}
클래스에 선언하여 사용하다면 state 같이 단독으로는 의미가 불명확한 단어도 '주소 클래스에 포함된 용어구나'라는 것을 알 수 있다.
클래스나 그런 것에 표현 할 수 없다는 변수 앞에 [addr] 같이 접두어를 붙여 사용하는 것도 방법 중 하나이다.
ex) addrState
Google Java Naming Guide
추가적으로 협업에서 사용되는 Google Java Naming Guide 몇 가지를 정리해 보고 넘어가자. (네이밍 규칙만)
Package Naming Guide
All lower case, no underscores (모두 소문자로 작성하며 언더바를 사용하지 않습니다.)
com.example.deepspace (O)
com.example.deepSpace (X)
com.example.deep_space (X)
Class Naming Guide
UpperCamelCase(대문자로 시작)
// 클래스는 명사, 명사구
Character, ImmutableList
// 인터페이스는 명사, 명사구, (형용사)
List, Readable
// 테스트 클래스는 Test로 끝나기
HashTest, HashIntegrationTest
- 클래스 이름은 일반적으로 명사 또는 명사구이다.
- 인터페이스 이름은 명사 또는 명사구(List) 일 수도 있지만 때로는 대신 형용사 또는 형용사 구 (Readable)를 사용하기도 한다.
- 테스트 클래스의 이름은 테스트중인 클래스의 이름으로 시작하고 Test를 끝에 붙여준다.
Methed Naming Guide
LowerCamelCase(소문자로 시작)
// 메서드는 동사, 동사구
sendMessage, stop
// junit 테스트에는 Underscore를 사용하기도 함
// <methodUnderTest>_<state> 패턴
pop_emptyStack
메서드는 동사 및 동사구로 표현한다. JUnit 테스트 메서드 이름에 밑줄이 표시되기도 하는데 이름의 논리적 구성 요소를 구분하는 위해 사용된다.
Constant Naming Guide
상수라고 표현하며, CONSTANT_CASE을 사용한다. 해당 방법은 모든 단어는 대문자로 사용하며 각 단어사이에 _를 이용하여 이어주는 방법이다.
static final int NUMBER = 5;
static final int PHONE_NUMBER = "000-0000-0000";
그 외의 상수가 아닌 필드, 지역변수, 파라미터 이름등은 LowerCamelCase(소문자로 시작)을 사용한다.
'Language > TDD, 클린코드, 리펙토링' 카테고리의 다른 글
[클린코드] 4장. 주석 (0) | 2023.12.14 |
---|---|
[클린코드] 3장. 함수 (with SOLID) (2) | 2023.12.11 |
[TDD] getter 대신 메시지를 던져라 (0) | 2023.09.03 |
[TDD] 테스트가 힘든 코드를 테스트 가능한 구조로 변경하기 (0) | 2023.08.29 |
클린코드 책과 제로베이스 [개발자와 함께 읽는 클린코드] 강좌를 기반으로 작성하였습니다.
Chapter 1. 깨끗한 코드
클린코드 1장에서는 어떤 코드가 깨끗한 코드이며 왜 깨끗한 코드를 사용해야 하는지 설명하고 있다.
나쁜 코드
코드를 읽게 되었을 때 '뭔가 이상하다. 변수의 의미도 모르겠고 중복코드가 많네. 포맷팅도 이상하고, 함수가 너무 뚱뚱한데?'라고 느낀 다면 나쁜 코드라고 볼 수 있다.
성능이 나쁜 코드
불필요한 연산이 들어가서 개선의 여지가 있는 코드
의미가 모호한 코드
이해하기 어려운 코드, 네이밍과 그 내용이 다른 코드
중복된 코드
비슷한 내용인데 중복되는 코드들은 버그를 낳는다. (재활용이 아닌 코드를 복붙 해서 여러 군데 사용하는 경우)
나쁜 코드가 나쁜 이유
나쁜 코드는 깨진 유리창처럼 계속 나쁜 코드를 만들어지게 한다.
깨진 유리창 법칙
깨진 유리창 하나를 방치해 두면 그 지점을 중심으로 범죄가 확산되기 시작한다는 이론이며, 나쁜 코드도 마찬가지로 방치해 두면 지속적으로 확산된다.
생성성 저하
나쁜 코드는 팀 생산성을 저하시킨다. 기술부채로 쌓인 프로젝트는 수정을 더 어렵게 한다.
새로운 시스템을 만들어야 한다. (재설계의 꿈)
현 시스템을 유지보수하면서, 대체할 새로운 시스템 개발은 현실적으로 매우 어렵다.
그럼 나쁜 코드는 왜 나오는 것일까?
일정 안에 프로젝트를 완성(기능을 완성)시켜야 되지 때문이다. 하지만 역설적이게도 나쁜 코드를 프로젝트를 진행하다 보면 생산성을 저하하기 때문에 오히려 일정이 딜레이 되는 문제가 발생하게 된다.
아까도 이야기했듯이 나쁜 코드를 쌓다 보면 영향 범위(강한 연관성)가 넓어지게 되므로 지속적으로 나쁜 코드를 양산하는 방식으로 진행하게 된다. (건드렸다가 다른 부분에 영향을 미칠까 봐..)
하지만 기술부채는 부메랑처럼 우리에게 다시 돌아온다.
1장에 나온 내용들이 사실 본인이 클린코드 책을 구매해서 공부를 해야겠다고 마음을 먹게 된 이유들이다. 많은 개발자들이 이미 레거시로 된 프로젝트를 한 번쯤은 맡아서 진행해 본 경험이 있을 것이다. 본인의 경우 그런 프로젝트를 떠맡아 본 적도 있고 실제 만들어 본 경험도 있다.
정해진 일정에 맞추다 보니 기능이 동작한다. 에만 초점을 맞추어 개발하였고 끝나고 보니 엄청난 레거시 프로젝트를 진행되어 있었다. 사실 이런 프로젝트는 유지보수 및 고도화 진행하기도 어렵다. 한 곳을 고치면 다른 데가 펑펑 터지기 때문이다. 그렇다고 재설계할 수 도 없다. 회사에서는 생산성(돈이 되는 작업) 있는 업무를 지속적으로 해야 되기 때문에 개발자가 책임 없이 짠 코드를 다시 수정을 기회는 잘 오지 않는다. 그래서 애초에 나쁜 코드를 만들지 않는 습관이 중요하다.
그래서 클린코드가 머야?
우아하고 효율적인 코드는 한 가지를 제대로 한다. - 비야네 스트롭스트룹 (C++ 창시자)
단순하고 직접적이며 잘 쓴 문장처럼 읽힌다. - 그래디 부치 (OOADA 저자)
읽기 쉽고 고치기도 쉬우며 테스트 케이스가 잘 작성되어 있다. - 데이브 토마스 (OTI창립자, 이클립스 전략의 대부)
손댈 곳 없이 주의 깊게 짰다는 느낌을 준다. 고칠 궁리를 하면 계속 다시 제자리로 돌아온다. - 마이클 페더스 (WELC 저자)
많은 유명 개발자들은 클린코드를 위와 같이 정의한다.
결론적으로 클린코드란?
- 성능이 좋은 코드
- 의미가 명확한 코드( = 가독성이 좋은 코드)
- 중복이 제거된 코드
Chapter 2. 의미 있는 이름 짓기
프로젝트 안에는 수많은 요소들이 존재한다. 프로젝트명, 패키지, 클래스, 메서드, 변수 등의 이름을 우린 부여할 수 있다. 이러한 수많은 요소들의 이름을 의미를 고민하지 않고 짓는다면 나쁜 코드를 만드는 지름길로 가는 것이다.
그럼 의미있는 이름 짓는 방법은 무엇이 있을까?
의미 있는 이름 짓기
1. 의미가 분명한 이름 짓기
의미 있는 이름을 짓는 것은 생각보다 쉽지 않고 고민하는데 시간적인 소요도 발생한다. 하지만 좋은 이름을 짓게 되면 그것으로 인해 절약되는 시간은 더 클 것이다.
int a
String b
// ..
System.out.printf("User Requested %s. count = %d", b, a);
// Console 결과물
// User Requested book. count = 3
위 코드를 보고 a, b 변수가 의미하는 것을 알 수 있는가? 아래 출력문을 보고 사용자가 요청하는 것에 대한 카운터를 출력한다. 정도 유추가 가능하고 최종적으로 Console 결과물이 나와야 정확히 무엇을 의미하는지 알 수가 있다.
변수 명만으로는 기능을 유추할 수 없으니 코드를 읽는 입장에서는 매우 난감하다.
int itemCount;
String itemName;
// ..
System.out.printf("User Requested %s. Count = %d", itemName, itemCount);
// Console 결과물
// User Requested book. count = 3
a, b가 아닌 변수명의 구체적인 의미를 담아 변경하였다. 변수 명만으로 변수가 아이템에 대한 이름과 카운터를 나타내는 것을 알 수 있다. 이렇게 의미를 담으면 코드 이해와 변경이 쉬워진다.
한 번 더 나아가보자.
class SalesItem {
ItemCode code;
String name;
int count;
}
// ..
SalesItem selectedItem = salesItemRepository.getItemByCode(purchaseRequest.getItemCode());
System.out.printf("User Requested %s. Count = %d", selectedItem.getName(), selectedItem.getCount());
// Console 결과물
// User Requested book. count = 3
위에서 선언한 itemName과 itemCount를 클래스로 묶어 단순한 변수명으로 변경이 가능하다. 어차피 클래스가 해당 변수가 어떤 것에서 파생되는 지를 알려주기 때문이다.
salesItemRepository에서 getItemByCode메서드를 호출하면 해당 메서드의 명칭을 보면 Code 조건에 따라 Item을 가져오는 메서드라는 것을 알 수 있다. 파리미터로 purchaseRequest.getItemCode()를 가져오는 것도 구매요청의 Item Code를 구나라는 것을 알 수 있다.
선언된 값인 SalesItem의 이름을 selectedItem이라 명명해 해당 조건에 선택된 아이템이다라는 것을 명확히 표현한다.
결론적으로 이름만으로 실제 구현부를 보지 않아도 어떤 데이터를 가져오는 구나를 알 수가 있다.
2. 루프 속 i j k 사용하지 않기
우리는 for문을 사용할 때 i, j, k 들의 용어를 많이 사용한다.
for (int i = 0; i < message.size(); i++) {
// ..
}
for문을 사용할 때 index를 의미하는 i를 사용하지 않고 advanced for(향상된 for문)을 이용하여 처리하자.
for (String message : message) {
// ..
}
배열의 index를 사용하는 경우(몇번째 순서인지가 알아내는 것이 중요하지 않다면)가 아니라면 굳이 i, j, k라는 변수를 선언하며 사용할 필요는 없다.
자바 8 이후에는 람다가 제공되므로 람다방식을 이용하는 것도 방법 중 하나이다.
message.stream().foreach{
message -> // ..
}
만약 꼭 필요하다면 i,j,k 대신 대체할 수 있는 용어를 사용하는 것도 좋은 방법이다.
- i, j -> row, col / width, height
- i, j, k -> row, col, depth
3. 통일성 있는 단어 사용하기
Member / Customer / User
Service / Manager
Repository / Dao
사용자(유저)를 나타내는 용어를 사용하는 사람에 따라 다르게 사용한다면 그것 또한 나쁜 코드가 될 수 있다. 그 외에도 Service , Repository 클래스를 만들 경우 Manager, Dao 등과 혼용하여 사용한다면 그것 또한 혼란을 줄 수 있으므로 나쁜 코드가 된다.
이런 경우에는 팀에서 협의를 통해 공통된 용어를 정해 사용하는 것이 좋다.
4. 변수명에 타입 넣지 않기
옛날에는 헝가리식 표기법이라고 해서 컴파일러가 자료형(타입)을 인지하지 않아 변수명에 같이 넣는 방식으로 많이 사용했다고 한다. 요즘에는 컴파일러가 많이 발전되었고 특히 자바진영에서는 이러한 걱정을 굳이 할 필요가 없다.
String nameStirng -> name
Int itmePriceAmount -> itemPrice
Account[] accountArray -> accounts
List<Account> accountList -> accounts, accountList
Map<Account> accountMap
public interface IShapeFactory -> ShapeFactory
public class ShapeFactoryImpl -> ShapeFactoryImpl, CircleFactory
- nameString은 이미 String 이라는 타입을 선언하고 있기 때문에 name이라고 표기한다.
- itemPriceAmount처럼 명칭에 중복된 의미를 가지면 정리한다. (여기선 price와 amonut가 중복되었다고 봤음)
- accountArray처럼 타입명을 붙여 사용하지 말자.
- List 타입에 경우 때때로 [변수 + List] 도 사용되기도 한다.
- Map도 대체될 수 있는 단어가 마땅히 없을 경우 Map을 붙여 사용하기도 한다.
- List 나 Map도 타입 중 하나이기 때문에 팀에서 사용을 지양하라고 하면 안 쓰면 될 것 같다.
- 인터페이스의 경우 옛날에는 앞에 I를 붙여 '너 인터페이스야'라고 명시적으로 많이 사용했지만 요즘에는 사용되지는 않는다.
- 구현 클래스에 Impl 를 붙여 사용하는 경우와 구현체의 기능을 나타나는 명칭 사용하는 경우로 나눤다.
- 팀에서 정한 규칙대로 사용하자.
5. 한 개념에 한 단어를 사용하라
이 부분을 사전 정의 하지 않으면 한 개념에 대해서 다양한 용어를 사용하는 것을 많이 봤다. (본인 포함)
만약 학생을 불러오는 메서드를 만든다고 했을때 아래 예시처럼 각각 다르게 사용된다면 그것 또한 나쁜 코드가 될 수 있다. 아래 3개 어떤 거든 통일해서 쓰는 게 읽기도 편하고 통일성도 줄 수 있다.
예) getStudent, fetchStudent, retrieveStudent
6. 해법 영역에서 가져온 이름을 사용해라
코드를 읽는 사람을 대부분 이쪽 종사자이다. 그러므로 전산용어, 알고리즘 용어 등 전문적인 용어를 사용해도 된다. 프로그래머에게 친숙한 기술 용어는 사용해도 무방하다.
예) AccountVisitor, JobQueue
그럼에도 적절한 용어를 없다면 도메인(문제 영역)에서 가져온 용어의 이름을 사용한다.
예) seller, buyer
7. 의미 있는 맥락을 추가해라
이름 하나로 스스로 의미가 분명한 이름은 생각보다 많지 않을 수 있다. 그렇기 때문에 클래스, 함수, 이름 공간 등에 넣어 맥락을 부여한다.
public class Address {
private String firstName;
private String lastName;
private String street;
private String state;
private String zipCd;
private String addr1;
private String addr2;
// ..
}
클래스에 선언하여 사용하다면 state 같이 단독으로는 의미가 불명확한 단어도 '주소 클래스에 포함된 용어구나'라는 것을 알 수 있다.
클래스나 그런 것에 표현 할 수 없다는 변수 앞에 [addr] 같이 접두어를 붙여 사용하는 것도 방법 중 하나이다.
ex) addrState
Google Java Naming Guide
추가적으로 협업에서 사용되는 Google Java Naming Guide 몇 가지를 정리해 보고 넘어가자. (네이밍 규칙만)
Package Naming Guide
All lower case, no underscores (모두 소문자로 작성하며 언더바를 사용하지 않습니다.)
com.example.deepspace (O)
com.example.deepSpace (X)
com.example.deep_space (X)
Class Naming Guide
UpperCamelCase(대문자로 시작)
// 클래스는 명사, 명사구
Character, ImmutableList
// 인터페이스는 명사, 명사구, (형용사)
List, Readable
// 테스트 클래스는 Test로 끝나기
HashTest, HashIntegrationTest
- 클래스 이름은 일반적으로 명사 또는 명사구이다.
- 인터페이스 이름은 명사 또는 명사구(List) 일 수도 있지만 때로는 대신 형용사 또는 형용사 구 (Readable)를 사용하기도 한다.
- 테스트 클래스의 이름은 테스트중인 클래스의 이름으로 시작하고 Test를 끝에 붙여준다.
Methed Naming Guide
LowerCamelCase(소문자로 시작)
// 메서드는 동사, 동사구
sendMessage, stop
// junit 테스트에는 Underscore를 사용하기도 함
// <methodUnderTest>_<state> 패턴
pop_emptyStack
메서드는 동사 및 동사구로 표현한다. JUnit 테스트 메서드 이름에 밑줄이 표시되기도 하는데 이름의 논리적 구성 요소를 구분하는 위해 사용된다.
Constant Naming Guide
상수라고 표현하며, CONSTANT_CASE을 사용한다. 해당 방법은 모든 단어는 대문자로 사용하며 각 단어사이에 _를 이용하여 이어주는 방법이다.
static final int NUMBER = 5;
static final int PHONE_NUMBER = "000-0000-0000";
그 외의 상수가 아닌 필드, 지역변수, 파라미터 이름등은 LowerCamelCase(소문자로 시작)을 사용한다.
'Language > TDD, 클린코드, 리펙토링' 카테고리의 다른 글
[클린코드] 4장. 주석 (0) | 2023.12.14 |
---|---|
[클린코드] 3장. 함수 (with SOLID) (2) | 2023.12.11 |
[TDD] getter 대신 메시지를 던져라 (0) | 2023.09.03 |
[TDD] 테스트가 힘든 코드를 테스트 가능한 구조로 변경하기 (0) | 2023.08.29 |