Programming/Clean-Code

Clean Code - 1. 의미 있는 이름 짓기

양디 2016. 10. 25. 11:59

이름 짓기의 중요성


코딩을 하다 보면 이름 짓기에 꽤나 많은 시간을 들이게 된다. 변수명, 함수명, 클래스 이름 등등...

다양한 속성들이 존재하는데, 각각의 것들은 이름으로 그 기능을 알 수 있는 것이 좋다.


개발 작업은 특별한 경우를 제외하고는 1인이 아닌 다수의 개발자가 팀을 이뤄 프로젝트를 진행한다.

자신이 만든 코드를 자신만 보는 경우는 드물고, 코드 리뷰를 통하여 함께 코드를 개선시키고 프로젝트를 진행시켜 간다.


따라서, 자신이 시간이 아주 많고, 할 일이 너무 없어서 자신이 짠 코드들을 일일이 다 설명해 주고 싶다면 코드를 자신만 이해할 수 있는 방법으로 프로그래밍 해도 좋다.


하지만, 그렇지 않기에 코드 그 자체를 보고 다른 사람이 이해할 수 있도록 짜주는 것이 바람직하다.


그럼 다양한 이름들을, 어떻게 짓는 것이 좋을까 ? 하는 의문이 든다.


다양한 언어에는 다양한 리터럴이 있지만, 그 제한이 대부분 강하지 않다.


변수를 i로 선언해도 좋고, o로 선언해도 똑같이 작동한다. 

따라서, 정형화되고 강제적인 규칙은 없으나, 객관적으로 이해하기 쉬운 방식을 고민해 볼 필요가 있다.


의도가 드러나는 이름

이름은 그 이름이 쓰이는 의도가 분명하게 드러나는 것이 좋다.

이렇게 말하면, 그건 당연한 것이 아닌가 ? 싶지만 실제로는 잘 지켜지지 않는 경우가 많다.

또한, 주석으로 변수, 함수, 클래스 를 설명해야 한다면, 이름이 잘 지어지지 않은 경우가 대부분일 것이다.


예를 들어, 이번 삼성 SW 역량 테스트에는 지네 게임이 나왔었다.

지네가 움직일 수 있는 방향은 동,서,남,북의 4개 방향이다.


이를 코드로 짰을때, 다음과 같은 코드라면 다른 사람이 이해하기 쉬울까 ?


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
a.d = 3// a는 지네, d는 방향
 
switch(a.d){
    case 1
        mve(); // 동쪽으로 이동한다.
        break;
    case 2:
        mvw(); // 서쪽으로 이동한다.
        break;
    case 3:        // 남쪽으로 이동한다.
        mvs();
        break;
    case 4:        // 북쪽으로 이동한다.
        mvn();
        break;
}
cs


위와 같은 코드는, 극단적인 표현이긴 하지만 실제로 이렇게 코딩하는 사람들도 있다.

의미 없는 변수의 이름과, 의미 없는 함수의 이름으로 인해 주석이 없다면 본인만 이해할 수 있는 코드가 된다.(나중엔 본인도 까먹는다.)


이를 다음과 같이 짜면 어떨까?


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
centipede.direction = WEST;
 
switch(centipede.direction){
    case EAST: 
        moveEast(); 
        break;
    case WEST:
        moveWest(); 
        break;
    case SOUTH:        
        moveSouth();
        break;
    case NORTH:        
        moveNorth();
        break;
}
cs


어떤가? 주석이 없어도, 분명히 이해할 수 있는 코드가 되었다.

작성자 뿐만 아니라 다른 사람이 보더라도 쉽게 이해할 수 있는 코드가 된 것이다.


위와 같이, 이름은 의도를 분명하게 드러내야 한다.


맥락을 생각하라.

변수명, 클래스명, 함수명을 지을 때에는 단순하게 그 대상만을 고려해서는 안된다.

전체적인 맥락을 고려해서 짓는 것이 좋다.


예를 들어, 위의 지네의 경우에는 머리와, 몸통, 꼬리의 위치를 가리키는 변수가 있다고 하자.

이를 C 언어의 구조체를 사용해서 짰을 경우, 다음과 같은 코드는 어떤가 ?


1
2
3
4
5
typedef struct Centipede{
    int *centipedesHead;
    int *centipedesBody;
    int *centipedesTail;
}Centipede;
cs


물론, 나쁘지 않다. 하지만, 굳이 이렇게 짤 필요가 있었을까?

머리, 몸, 꼬리의 포인터는 이미 Centipede라는 구조체 내부에 선언되어 있다는 것이 명백하다.

따라서, 의도를 정확하게 해 준 것은 좋았지만, 불필요한 행동이었다는 점에서 개선될 여지가 존재한다.


1
2
3
4
5
typedef struct Centipede{
    int *head;
    int *body;
    int *tail;
}Centipede;
cs


이렇게만 짜줘도, 머리 몸통 꼬리가 지네에 속해있다는 것은 분명하게 보인다.


좋은 이름의 판단 기준들

이름은 구체적으로 명확하게 판단 기준이 존재하지 않는다.

이 이름은, 아, 10점 만점에 6점이야 ! 하는 기준이 없기 때문에, 기준 또한 주관적이며 모호하다.

따라서, 모든 사람들의 주관에 이해될 수 있을 법한 이름을 짓는 것이 좋다.


첫째, 이름은 기억하기 쉬워야 한다.

기억하기 쉬운 이름은 어떤 이름인가에 대해 생각해 보자면,

첫째로 발음하기 쉬우며, 

둘째로 이미 알고 있는 단어이며, 

셋째로 단어의 의미와 기능이 실제로 동일한 것이다.

첫째와 둘째를 결합해보자면, 예를 들어 한국인이 코딩을 한다고 생각해보자. 그리고, 그 코드를 미국인이 본다고 가정했을때, 다음과 같은 것은 어떤가?


1
char *hangeul;
cs


물론 한글은 이미 세계적으로도 과학적으로도 입증된 최고의 언어 중 하나이지만, 미국인이 한글을 모를 때 이 변수를 기억할 수 있을까?

첫째로 발음조차 할 수 없는 단어이다. 행게울? 행굴 ? 혼란스러워 하는 도중에 이미 기억에서 사라져 있을지도 모른다.

둘째로, 단어가 무슨 의미인지를 모른다. 

따라서, 객관적으로 이해하기 쉬운 단어를 사용하는 것이 좋을 것이다.


둘째, 자신의 센스를 이름에 부여하지 않는 것이 좋다.

여기에서 센스는 다양한 센스를 뜻한다.

유머 센스 또한 적용된다.

예를 들어, 화면을 지우는 함수를 만들 때에

clearView() 함수는 누구나 명확하게 이해할 수 있다.

nuclearBomb() 함수를, 핵폭탄처럼 화면을 깨끗하게 지우는 뜻으로 쓸거야 ! 라고 지었다면..

이는 지나치게 주관적인 센스가 개입되었다. 좋지 않다.


셋째, 한 개념에 한 단어를 사용하자.

예를 들어, add라는 함수를 만들었다.

add(a, b)는 a와 b를 더하는 함수로 사용했다면,

list.add(a)는 사용하지 않는 것이 좋다. 이 함수는 list에 a 노드를 집어 넣어주는 것이기 때문이다.

실제로 덧셈을 할 경우에만 add 개념을 사용하고, 뒤의 경우에는 insert를 사용해주는 것이 바람직하다.

또, accountList 라는 변수가 있다면, 프로그래머는 이 변수를 보고 Linked List를 생각하게 될 것이다.

만약 단순하게 목록이나 다수의 account를 생각했다면, accounts 또는 accountGroup으로 짓는 것이 좋다.

list나 arr 등 프로그래머에게 다른 의미를 떠오르게 할만한 것은 조심해서 사용하는 것이 좋다.

따라서, 개념에 따라 일관성 있게 코딩하자 !


그 외에 변수는 소문자로 시작, 클래스는 대문자로 시작한다는 규칙이나

변수와 클래스는 명사, 메서드나 함수는 동사로 짓는다는 규칙 등이 있다.


또, 단순하게 일회성으로 사용하는 변수들은 사용하기 편하게 i , j, k 등으로 임시적으로 사용해도 이해할 수 있다.

그러나, 넓은 유효 범위를 지닌 객체들은 그에 마땅한 이름을 지어주자.




누구나 보기 쉽고 이해하기 쉬운 코드를 지향하자 !

댓글