서론
JavaScript에서 클린 코드를 작성하는 것은 코드의 가독성과 유지 보수성을 높이는 데 중요한 역할을 한다. 특히 반복문과 조건문을 줄이고, 들여쓰기를 최소화하는 것은 코드의 복잡성을 줄이는 데 매우 중요하다. 반복문과 조건문을 무조건 쓰지 말아야하는 것은 아니지만 적절하게 대체하면 코드의 가독성과 유지 보수성을 높일수 있기에 이 글에서는 해당 목적을 달성하는 방법에 대해 알아보고자 한다.
조건문 간소화하기
객체 Mapping 사용하기
조건이 한 두개일 때는 괜찮으나 조건이 여러개로 분기하게 되면 코드의 길이가 상당히 길어지는 것을 느낄 수 있다. 이럴때 조건문을 줄이는 한 가지 방법은 객체 mapping을 사용하는 것이다. 예를 들어, 여러 조건에 따라 다른 행동을 해야 할 때, 각 조건을 객체의 키로, 해당 조건에서 실행할 함수를 값으로 mapping할 수 있다. 이렇게 하면 복잡한 if-else 블록 대신 간단한 객체 조회로 같은 로직을 수행할 수 있다.
const respond = (input) => {
if (input === 'a') {
console.log('A');
} else if (input === 'b') {
console.log('B');
} else {
console.log('잘못된 입력입니다.');
}
};
respond('a'); // A
respond('b'); // B
respond('c'); // 잘못된 입력입니다.
예를 들어 사용자의 입력에 따라 다른 결과를 출력하는 함수를 짠다고 생각해보자. 조건이 적을때는 괜찮으나 조건이 늘어난다면 코드의 길이가 상당히 길어질 것을 알 수 있다. 이를 객체 mapping을 사용하면 코드를 유지보수 편하게 수정할 수 있다.
const responses = {
'a': () => console.log('A'),
'b': () => console.log('B'),
'default': () => console.log('잘못된 입력입니다.')
};
const respond = (input) => {
const action = responses[input] || responses['default'];
action();
};
respond('a'); // A
respond('b'); // B
respond('c'); // 잘못된 입력입니다.
다음과 같이 객체 mapping을 쓰면 사용자의 입력에 따른 출력을 하는 함수와 함수의 내용을 분리할 수 있다.
Filter Callback 함수 사용하기
Array의 filter 메서드를 사용하면 배열에서 특정 조건을 만족하는 요소만을 쉽게 추출할 수 있다. filter 메소드는 콜백 함수를 인자로 받으며, 이 콜백 함수는 각 요소에 대해 true 또는 false를 반환합니다. 이를 통해 복잡한 조건문을 사용하지 않고도 원하는 데이터를 필터링할 수 있다.
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const evenNumbers = numbers.filter(number => number % 2 === 0);
console.log(evenNumbers); // [2, 4, 6, 8, 10]
물론 이 방법도 장단점은 있다. 코드의 가독성은 떨어질 수 있다는 것이다. 코드의 가독성도 유지하기 위해 하나의 컴포넌트는 하나의 기능만 담당하도록 짜는 것이 좋을 것이다.
반복문 대체하기
고차 함수 사용하기
JavaScript의 배열 메서드인 map, filter, reduce 등의 고차 함수를 활용하여 반복문을 대체할 수 있다. 이러한 고차 함수들은 기존의 for 또는 while 반복문을 대체할 수 있으며, 코드를 더 간결하게 만들어 준다. 또한 고차함수를 쓰면 좋은 이유는 단순 코드의 간결함만을 위한 것이 아니다. 자바스크립트에서 고차함수를 써야하는 이유는 이 글에 설명해놓았다.
const numbers = [1, 2, 3, 4, 5];
// for문으로 제곱된 수 배열 리턴
const squaredNumbers = [];
for (let i = 0; i < numbers.length; i++) {
squaredNumbers.push(numbers[i] * numbers[i]);
}
console.log(squaredNumbers); // [1, 4, 9, 16, 25]
// map으로 제곱된 수 배열 리턴
const squaredNumbers = numbers.map(number => number * number);
console.log(squaredNumbers); // [1, 4, 9, 16, 25]
들여쓰기 최소화하기
컴포넌트 분리하기
코드를 작성할 때 하나의 컴포넌트가 하나의 기능만을 담당하게 하는 것은 매우 중요하다. 단위테스트를 쉽게 만들어줄뿐만 아니라 문제가 생겼을 때 단방향 흐름을 통해 어디서 문제가 생겼는지 파악하기 쉬워지기 때문이다. 이를 위해 함수 각각의 역할을 데이터, 액션, 계산으로 구분할 수 있다. 이를 통해 각 컴포넌트의 역할이 명확해지고, 코드의 복잡성이 줄어든다. 데이터는 애플리케이션의 상태, 순사한 값이며 계산은 순수함수로 입력으로 얻은 출력이다. 마지막으로 액션은 사용자와 상호작용하여 side effect를 일으키는 행동이다. 이들을 분리하여 컴포넌트 재사용성을 높히고 단위 테스트를 편하게 할 수 있다.
일반적으로 한 메소드에서 인자는 3개 이하로 받는 것이 좋다고 알려져 있고 한 메소드에 들여쓰기는 깊이 2~3이하로 하는 것이 좋기에 컴포넌트를 잘 분리해서 클린코드를 짤 수 있길 바란다.
'JS' 카테고리의 다른 글
[JS] Javascript의 프로토타입과 상속: 개념과 동작 이해 (0) | 2024.01.12 |
---|---|
[JS] Javascript에서의 Closures (1) | 2024.01.11 |
[JS] Javascript에서의 this (1) | 2024.01.09 |
[JS] 반복문 대신 고차함수를 쓰는 이유 (0) | 2024.01.07 |
API 응답과 빈 값: HTTP 상태 코드 200과 204 그리고 404 간의 선택 (0) | 2024.01.03 |