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