일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- 회고
- frontend
- 프론트엔드
- 클린코드
- MFA
- MicroFrontEnd
- server component
- JavaScript
- CustomHook
- 티스토리챌린지
- 자바스크립트
- TypeScript
- Web
- 아키텍처
- 오블완
- 리액트
- CRA
- vite
- 리팩토링
- provider 패턴
- virtaullist
- context.api
- 웹워커
- 이것저것
- sharedworker
- 에세이
- radixui
- 합성 컴포넌트
- react
- Webworker
- Today
- Total
Lighthouse of FE biginner
[클린코드] 함수의 클린코드 본문
Overview
이전 게시글에서 함수에 대해서 스터디를 진행 했습니다. 이번 포스팅에서는 함수의 클린 코드에 대해서 살펴보겠습니다.
함수의 클린 코드
IIFE 사용을 지양한다.
가급적이면 즉시 실행 함수(IIFE: Immediately Invoked Function Expression)를 사용하지 않습니다.
(() => {
console.log(this);
})();
요즘의 프론트엔드는 모듈화를 지향합니다. IIFE 함수는 즉시 실행이 되기 때문에 정의한 함수를 재사용 할 수 없습니다. IIFE 함수는 디버깅이 어렵다는 단점이 있고 함수의 선언문이 즉시 실행이 되기 때문에 IIFE 함수가 지속해서 쌓이다 보면 메모리 누수에 유의해야 합니다.
중첩 함수에서의 스코프
중첩 함수를 선언할 시 스코프에 주의합니다. 그리고 클로저 함수를 작성할 시 메모리 누수에 주의합니다. 클로저 함수를 사용할 경우 외부 함수 실행 컨텍스트가 메모리에 계속 유지가 됩니다.
모던 브라우저는 클로저 함수의 메모리 누수를 방지하기 위해 메모리 최적화가 잘 되어있습니다. 하지만 개발자로써 어떤 케이스에서 메모리 누수가 발생할 수 있을지 잘 알고 코딩해야 합니다.
단일 책임의 원칙과 순수 함수
하나의 함수는 하나의 일만 수행해야 합니다. (단일 책임의 원칙)
가급적 함수는 외부 상태를 변경하지 않으며 외부 상태에 의존하지 않고, 예측 가능한 순수 함수로 만들어야 합니다.
const doingThings = async () => {
const data = await fetch(url).then((data) => data.json());
const parsedData = data.map((res) => res + ".json");
//...
}
위 두 가지 항목을 예제 코드로 살펴봅시다. 아래 함수는 어떤 프로세스를 진행하기 위한 함수입니다. 해당 함수에서는 데이터를 불러오는 일과 데이터를 파싱하는 일을 하고 있습니다. 이러한 케이스에서 doingThings라는 함수는 어떤 일을 하는지 명확하지 않기 때문에 추후 유지 보수에 어려움을 겪을 수 있습니다.
const getData = async () => {
const data = await fetch(url).then((res) => res.json());
return data;
}
const parsedData = (data) => {
return data.map((res) => res + ".json")
}
const makeData = async () => {
const data = await getData();
const parsedData = parsedData(data);
}
두 가지 원칙을 반영해 코드를 리팩토링 했습니다.
원래의 코드보다는 행이 길어졌지만 함수를 단 하나의 일만 수행하도록 분리를 했고, parsedData라는 함수는 매개변수를 사용해 값을 return 하기는 함수이기 때문에 항상 같은 input일 경우 같은 output을 내겠구나 하고 예측이 가능합니다.
이런 식으로 함수는 하나의 일만 하고 항상 예측이 가능해야 합니다. 그래야 유지 보수에 쉽고 예측 가능한 신뢰성 높은 소프트웨어를 만들 수 있습니다.
매개변수
함수의 매개 변수는 가급적 3개 이하로 디자인 해야 합니다. 많은 인자가 필요하다면 객체를 넘기는 것이 이상적입니다.
함수는 가급적 적은 매개변수를 가지고 있어야 합니다. 이 말은 함수에 많은 매개변수를 전달해서는 안된다는 것이 아닌 클린 코드를 위해서는 매개변수의 개수가 많아서는 안된다는 것 입니다.
const getData = async (bookId, reviewId, authorName, bookCode, userName) => {
const data = await fetch(`http://api.com/api/book/${bookId}/review/${reviewId}?author=${authorName}&bookCode=${bookCode}&userName=${userName}`)
return data;
}
getData(1,2,'모던자바스크립트','ef1','프론트')
위 getData 함수는 데이터를 호출하는 함수입니다. 함수에서는 5개의 매개변수를 받고 있고, 호출하는 곳에서 매개변수 5개를 전달하고 있습니다.
혹시 getData를 호출할 때 매개변수로 전달하는 리터럴이 어느 값으로 전달되는지 직관적으로 파악할 수 있을까요?
5개가 넘어가는 매개변수는 어떤 값으로 전달하는지 파악하기도 어렵고 디버깅 또한 쉽지 않습니다. 이런 케이스는 객체를 통해 값을 넘기도록 합시다.
const getData = async (params) => {
const { bookId, reviewId, authorName, bookCode, userName } = params
const data = await fetch(`http://api.com/api/book/${bookId}/review/${reviewId}?author=${authorName}&bookCode=${bookCode}&userName=${userName}`)
return data;
}
getData({
bookId: 1,
reviewId: 2,
authorName: '모던 자바스크립트',
bookCode: 'ef1',
userName: '프론트'
})
매개변수를 객체로 넘겨주니 함수를 호출하는 곳에서 어떤 값으로 넘겨주고 있는지 직관적으로 알 수 있습니다. 많은 매개변수를 사용하는 경우 반드시 객체를 통해서 값을 넘겨주도록 합시다.
이른 반환(early return)을 주의해서 사용하자.
early return은 함수를 중간에 중단할 수 있으니 유용한 문법입니다. 하지만 early return을 잘못 사용하는 경우 소프트웨어가 예측하기 어렵고 디버깅이 어려울 수 있습니다. early return을 사용하지 않고 if 조건을 통해서 특정 프로세스를 넘길 수 있는 경우에는 if 조건문을 신경쓰도록 하고, early return을 사용하는 경우에는 반드시 소프트웨어의 흐름이 예측 가능하도록 만들도록 합시다.
// bad
useEffect(() => {
if (!api) return;
api.~~~~
}, [])
// good
useEffect(() => {
if (api) {
api.~~~
}
}, [])
재귀 함수의 무한루프
재귀 함수를 선언할 시 무한 루프에 주의합니다. 반드시 루프를 exit 할 수 있는 조건이 존재해야 합니다.
'클린코드' 카테고리의 다른 글
[클린코드] 반복되는 값, 리터럴 (1) | 2024.08.22 |
---|---|
[클린코드] TypeScript `any` (0) | 2024.08.15 |
[클린 코드] 가독성 좋은 코드 - 변수 (2) | 2024.06.17 |