[Clean Coding] 2. Meaningful Names

라을·2024년 10월 9일

Clean Coding

목록 보기
2/10

들어가기 앞서 코드 몇개를 살펴보자

for(i=1; i<=n; i++)
	flag[i] = true;
    
for(i=2; i<=n/2; i++){
	j=i+1;
    while (j<=n){
    	flag[j] = false;
        j=j+i;
    }
}

for(i=1; i<=n; i++){
	if(flag[i])
    	System.out.println(i + "is prime");
}

이 코드를 읽고 의도를 알아차리기 위해서는 for문을 돌며 직접 계산을 해야하거나, 마지막에 프린트문을 보고서야 prime number를 출력하려고 하는구나 하고 알 것이다.

다음 코드를 보자

for(primeCandidate = 1; primeCandidate <= max; primeCandidate++)
	isPrime[primeCandidate] = true;

for(int facotr=2; factor<=max/2; factor++){
	factorableNumber = factor + factor
    while(factorableNumber <= max){
    	isPrime[factorableNumber] = false;
        factorableNumber = factorableNumber + factor;
   }
}

 for (primeCandidate = 1; primeCandidate <= max; primeCandidate++)
 	if (isPrime[primeCandidate])
 		System.out.println(primeCandidate +is prime.)

다음 코드는 변수명을 읽을 때부터 바로 prime number를 계산하려고 하려는 의도가 파악이 가능하다!

다른 예시를 또 보자

def func(x):
	a=x.split()[0]
    b=x.split()[1]
    return a,b
    
print(func('Tom Cruise'))
def split_name(full_name):
	first_name = full_name.split()[0]
    last_name = full_name.split()[1]
    return first_name, last_name

print(split_name('Tom Cruise'))

첫 번째 함수에서는 결과값을 보고 나서야 성과 이름을 분리하려고 하는 것임을 알 수 있는 반면에, 두 번째 함수에서는 함수명에서부터 의도가 파악되며, 변수명을 통해 어디에 성과 이름이 저장되는지도 파악할 수 있다.

또 다른 예시를 보자

역시 의도가 보이지 않는다
좋은 코드의 예시는 다음과 같을 것이다

function replaceZWithPercent(inputString) {
    let result = "";
    for (let i = 0; i < inputString.length; i++) {
        let currentChar = inputString.charAt(i);
        if (currentChar === "Z") {
            result += "%";
        } else {
            result += currentChar;
        }
    }
    return decodeURIComponent(result);  // decodeURIComponent is a safer alternative to unescape
}

let someVariable = 0;

이처럼 작성자가 아닌 사람이 코드를 읽었을 때 그 코드가 어떤 의도로 작성된 코드인지 쉽게 파악할 수 없다면 나쁜 코드에 해당하는 것이다!

본인의 코드가 나쁜 코드라면 바로 refactoring을 하자~!! (일단 나부터~~~)


이제 본격적으로 좋은 이름을 짓기 위한 방법에 대해 알아보자

✒️ Meaningful Names

변수, 함수, 매개변수, 클래스, 패키지 등에는 모두 이름이 붙는다.

이 이름들을 만들 때 어떤 것이 좋은 이름이라고 했쥬?

의도가 드러나는 이름이 좋은 이름이다!

  • 왜 존재하는가
  • 무엇을 하는가
  • 어떻게 사용되는가

가 드러나는 의도가 보여야 한다!

좋은 이름을 만드는데는 시간이 걸린다. 하지만, 앞으로의 작업에서는 시간을 더욱 세이브 해주는 역할을 하게 될 것이다.

In worst cases... 몇개월 뒤 내가 작성한 코드를 다시 봤을 때 왜 그렇게 작성했는지 아예 모르게 되는 경우가 발생할 수 있음

의도 드러나는 이름을 사용한 예시를 순차적으로 살펴보자

  1. first stage
public List<int[]> getThem(){
	List<int[]> list1 = new ArrayList<int[]>();
    for(int[] x : theList)
    	if(x[0] ==4)
        	list1.add(x);
    return list1;
  • getThem 이 무엇을 가져오는 것인지 알 수 없음
  • theList안에 무엇이 있는건지 알 수 없음
  • x[0]에서 0이 얼마나 중요한 역할을 하는지 알 수 없음
  • 숫자 4의 중요성 역시 알 수 없음

  1. improved code
public List<int[]> getFlaggedCells(){
	List<int[]> flaggedCells = new ArrayList<int[]>();
    for (int[]  cell : gameBoard)
    	if(cell[STATUS_VALUE]==FLAGGED)
        	flaggedCells.add(cell);
    return flaggedCells;
  • int[]가 ArrayList안에 있으니 어렵게 느껴질 뿐더러 어떤 역할을 하는지 제대로 알기 어려움

  1. further improved code
public List<Cell> getFlaggedCells(){
	List<Cell> flaggedCells = new ArrayList<Cell>();
    for (Cell cell: gameBoard)
    	if (cell.isFlagged())
        	flaggedCells.add(cell);
    return flaggedCells;
  • Cell 클래스를 사용하여 isFlagged()라는 함수로 더욱 직관적인 코드를 작성할 수 있음

📌 의미있는 변수명 작성하기

🔻 피해야 할 것

📍 잘못된 정보 피하기

  • ex. hp, sco, cal, XYZControllerForEfficientHandlingOfStrings vs. XYZControllerForEfficientStorageOfStrings (과하게 복잡함)

  • 데이터 타입이 변수명에 쓰일 경우

    • ex. accountList : 정말 list 형태가 아닌 이상 사용하지 말것!

      • Account[] accountList (x)
      • Account accountList (x)
      • List[Account] accountList (0) (원래 <> 이거 사용해야함)
    • 배열명은 복수형으로 작성하는 것이 좋음

      • Account[] account (x)
      • Account[] accounts (0)
  • 폰트 주의

    영문자 'L'을 l로, 영문자 'o'를 O로 되도록이면 사용하지 말것 - 1과 0하고 헷갈리기 때문

📍 헝가리안 표기법 피하기

헝가리안 표기법은 현대 언어에서 더 이상 필요하지 않다. 변수의 타입은ㄹ 이름에 포함시키는 방식인데, 컴파일러가 타입을 처리하기 때문에 오히려 코드를 읽기 어렵게 만든다

또한, m_ 같은 접도어를 사용하는 것은 더 이상 필요하지 않음!


📍 머릿속 매핑 피하기

독자가 변수 이름을 보고 다른 단어로 번역을 해야하는 경우는 없어야 한다

예를 들어, i,j,k를 for문에서 사용했을 때 i는 각 server, j는 각 client, k는 각 service를 나타낸다고 했을 때, for문을 돌때 독자는 머릿속에서 계속 매핑을 해야할 것이다

📍 재미있는 이름 피하기

재미를 위한 이름은 피해야함


🔻 해야할 것

📍 동사 사용하기

✔️ 클래스명

명사나 명사절 사용하기! => Class는 동사를 사용하지 말아야 함!

하지만 너무 일반적인 의미를 가지는 단어는 피해야 함 : ex. Manager, Processor, Data, Info

✔️ 메소드명

동사나 동사구 사용하기!

ex. postPayment, deletePage

다음 prefixes 사용하기

  • Accessors : get
  • Mutators : set
  • Predicates : is

📍 의미있는 구별 만들기

  • 단지 변수를 다르게 생성하기 위해서 숫자를 추가하거나 노이즈 단어 작성하지 말 것!
    • ex. a1, a2,..,a10

이러한 이름들은 작성자의 의도에 대한 실마리를 전혀 제공하지 않음!

  • 의미없는 구별은 피하기

    • ex. Product, ProductInfo, ProductData처럼 차이가 없는 이름을 사용하는 것을 피해야함. 이름이 달라지면 그에 따른 차이가 있어야 함!
  • 불분명한 노이즈 단어 피하기

    • a, an, the
    • theMessage는 message와 구별가능하지 않음
  • 쓸모없는 단어 피하기

    • name, nameString : 이름이 float형이진 않을거잖아...
    • Customer, CustomerObject : 구별을 하기 위해 무엇을 이해해야 하나요?

📍 발음 가능한 이름 사용

genymdhms 처럼 발음할 수 없는 혹은 발음하기 어려운 단어를 사용하면 이야기를 나눌 때 서로 알아듣기 어려워짐


📍 검색 가능한 이름 사용

코드에서 변수를 쉽게 검색할 수 있는 이름을 사용하는 것이 좋다

예를 들어, MAX_CLASSES_PER_STUDENT는 쉽게 검색이 가능하지만, 숫자 8은 검색하기 어렵다

루프에 사용되는 i,j,k 같은 이름은 허용되지만, 중요한 변수는 검색하기 쉬운 이름을 사용하는 것이 좋다

📍 하나의 개념에 하나의 단어 사용하기

무슨 말이냐하면, 예를 들어 DB에서 데이터를 가져와야할 때 fetch()라고 했다가 retrieve()라고 했다가 get()이라고 했다가 하지 말라는 것이다. 일관성 있게 사용할 것!

controller, manager, driver 혹은 deleteItem(), removeItem()도 비슷한 예가 되겠다.

하지만 다른 목적을 가졌다면, 다른 단어를 사용해야한다!

예를 들자면

  • 기존 두 값을 더하기 → add()
  • collection에 값 넣기 → add() [X]
    • insert() [O]
    • append() [O]

📍 적절한 도메인 이름 사용하기

  • 해결 도메인 이름 사용하기

    • 당신의 코드를 읽는 사람들은 프로그래머들일 것이다
    • 그러니 컴퓨터과학 용어, 알고리즘명, 패턴 명들을 사용하라
      • ex. JobQueue, ServerSingleton
  • 문제 도메인 이름 사용하기

    • 예를 들어 수학 영역에서는 x,y를 그냥 사용하는게, horizontalPosition, verticalPosition을 사용하는 것보다 나음

📍 의미있는 문백 추가하기


profile
욕심 많은 공대생

0개의 댓글