클린 코드란 무엇이길래 - 코드 가독성

2024년 12월 08일
8분

클린 코드

클린 코드란 무엇일까? 글쓰기로 예를 들어보겠습니다. 누군가 써놓은 글이 의미를 알 수 없고 난잡한 글일 때 그 글을 이해하기 어려울 것이다. 코드도 결국엔 글이다. 이해하기 어려운 글(코드)은 사람들에게 오해를 불러 일으킬 수 있다. 난잡하고 요상한 코드는 이 코드가 무엇을 의미하고 뭘 하고 싶은지 알 수 없게 한다.
그렇기에 우리는 코드를 작성할 때 읽기 쉬운 방향으로 변경하도록 노력해야한다.

도서 Clean Code에 이런 말이 있다.

"유지보수 하기 쉽게 코드를 작성하고 코드에 의도를 담아라. 6개월 뒤에 그 코드를 다시 보는 사람은 아주 높은 확률로 바로 너다."

지금 나에게만 정리되어 보이고, 내 눈에만 잘 읽히는 코드는 아무 의미가 없다.

우리는 코드를 단순히 동작하게 작성하는 것에서 남이 봐도 이해할 수 있도록 작성하는 것으로 코드를 바라보는 관점을 변경해야 한다.

코드 퀄리티 & 가독성 올리기

코드의 퀄리티와 가독성을 증진시켜주는 몇 가지 방법들에 대해 알아보겠습니다.

1. 함수의 분리

우선 함수의 역할과 책임이 다른 것을 명확히 파악하고 분리하는 것이 중요하다. 함수의 분리는 여러 함수들이 어떤 동작을 하는지 정확하게 예측할 수 있도록 하는 것에 의미가 있다.

우선 아래 예시를 보도록 하겠습니다. (아래 예시들에서 ...은 스프레드 문법이 아닌 내용의 축약을 나타냅니다.)

나쁜 예

//bad
const someArray = [...]
 
//bad
someArray.filter((item)=>{ ... })
         .map((item)=>{ ... })
         .forEach((item)=>{ ... })

위 코드는 메서드체이닝을 이용하여 각각의 메서드 안에서 모든 로직을 처리하고 있다. 예시 코드가 아닌 축약되지 않은 실제 로직이라면 코드가 길어지고 각 메서드 내에서 어떤 동작을 하는지 알아보기 힘들 수 있다.

좋은 예

함수를 따로 정의하고 호출하는 코드로 변경해보자.

const checkValid = (item) => { return boolean; }
const itemToAnotherItem = (item) => { ... return anotherItem; }
const doSomething = (item) => { ... }
 
someArray.filter(checkValid)
         .map(itemToAnotherItem)
         .forEach(doSomething)

위 코드는 배열 메서드 내에서 로직을 처리하지 않고 따로 정의해둔 함수를 사용하여 데이터 처리를 하고 있다. 전체 코드의 총량은 길어질 수 있다. 하지만 함수의 이름만 봐도 각 메서드내에서 어떤 동작을 수행하는지 명확하게 파악하기 쉽다는 장점이 있다.

2. 한 가지 동작만 하게 하기 (단일 책임 원칙)

함수는 한 가지 동작만을 해야하고 이름도 그에 맞게 지어야 한다.
아래 예시를 보자.

// bad
const calculate = (n1, n2, op) => {
  if (op == "*") {
    return n1 * n2;
  } else if (op == "+") {
    return n1 + n2;
  } else if (op == "-") {
    return n1 - n2;
  } else {
    return n1 / n2;
  }
};
 
//good
function add(n1, n2) {
    return n1 + n2;
}
 
function minus(n1, n2) {
    return n1 - n2;
}
 
function multiply(n1, n2) {
    return n1 * n2;
}
 
function divide(n1, n2) {
    if(n2 != 0) {
        return n1 / n2;
    } else {
        console.log("Error: Division by zero is not allowed.");
        return null;
    }
}

3. 매개변수는 최대한 적게

함수의 매개변수의 이상적인 개수는 0개이다. 많아질수록 가독성이 낮아질 수 있거나, 함수가 하나의 동작만 한다면 매개변수가 많을 이유가 없다

  • 매개변수는 최대한 두 개를 넘지 않게 구현하는 것이 좋다.
  • 매개변수로 boolean을 넘기지 않도록 해야한다. boolean을 넘기면 내부에 조건문이 존재한다는 것이고 이는 두 가지 이상의 동작을 한다는 의미이기 때문이다.

나쁜 예

아래 코드는 문자열과 boolean을 매개변수로 전달 받아 로직을 처리하는 함수이다. 하나의 함수에서 조건과 값의 반환까지 처리하고 있다.

function makeFullName(firstName, lastName, isEnglish) {
    if (isEnglish) {
        return lastName + firstName;
    } else {
        return firstName + lastName;
    }
}

좋은 예

아래 코드는 값을 반환하는 로직과 조건 로직이 분리되어 있다. 즉, 모든 로직이 분리되어 있어 한 가지 동작만을 수행하고 있다.

let name = {
    first: 'John',
    last: 'Doe'
};
 
if(isEnglish){
    makeKoreanFullName(name)
}else{
    makeEngName(name)
}
 
function makeKoreanFullName(name) {
    return name.first + name.last;
}
 
function makeEnglishFullName(name) {
    return name.last + name.first;
}

정리

위의 정리된 내용이 무조건 옳다라고 받아들이면 안된다. 클린 코드는 좋은 코드를 작성하기 위한 방법론 중 하나일 뿐이고 너무 맹신하는 것인 좋지 않다. 특히 클린 코드의 모든 내용을 지키면서 코딩을 하면 함수가 너무 많아질 수밖에 없고, 이는 오히려 가독성을 해칠 위험이 있을 수 있다.

나도 내용을 정리하며 클린 코드 예시가 좋아보이는 것도 있지만 굳이..? 생각이 드는 예시도 있다. 따라서 무조건 규칙을 지키기보다 본인의 주관을 확립하고 일관성만 잘 지켜진다면 괜찮지 않을까 생각한다.

클린코드

#1 [클린코드 - 의미 있는 변수명]
#2 [클린코드 - 조건과 탈출]
#3 현재 글 - [클린코드 - 코드 가독성]