같은 이름을 가지는 함수나 변수는 동일한 동작을 해야 해요. 작은 동작 차이가 코드의 예측 가능성을 낮추고, 코드를 읽는 사람에게 혼란을 줄 수 있어요.
// 이 서비스는 `http`라는 라이브러리를 쓰고 있어요
import { http as httpLibrary } from "@some-library/http";
export const http = {
async get(url: string) {
const token = await fetchToken();
return httpLibrary.get(url);
}
};
이 코드는 기능적으로 문제가 없지만, 읽는 사람에게 혼란을 줄 수 있음.
http.get
을 호출하는 개발자는 이 함수가 원래의 HTTP 라이브러리가 하는 것처럼 단순한 GET 요청을 보내는 것으로 예상하지만, 실제로는 토큰을 가져오는 추가 작업이 수행됨.
개선해보기
서비스에서 만든 함수에는 라이브러리의 함수명과 구분되는 명확한 이름을 사용해서 함수의 동작을 예측 가능하게 만들 수 있음.
또한, getWithAuth
라는 이름으로 이 함수가 인증된 요청을 보낸다는 것을 명확하게 전달할 수 있음
// 이 서비스는 `http`라는 라이브러리를 쓰고 있어요
import { http as httpLibrary } from "@some-library/http";
// 라이브러리 함수명과 구분되도록 명칭을 변경했어요.
export const httpService = {
async getWithAuth(url: string) {
const token = await fetchToken();
// 토큰을 헤더에 추가하는 등 인증 로직을 추가해요.
return httpLibrary.get(url, {
headers: { Authorization: `Bearer ${token}` }
});
}
};
API 호출과 관련된 Hook들처럼 같은 종류의 함수나 Hook이 서로 다른 반환 타입을 가지면 코드의 일관성이 떨어져서, 같이 일하는 동료들이 코드를 읽는 데에 헷갈릴 수 있어요.
import { useQuery } from '@tanstack/react-query';
function useUser() {
const query = useQuery({
queryKey: ['user'],
queryFn: fetchUser
});
return query;
}
function useServerTime() {
const query = useQuery({
queryKey: ['serverTime'],
queryFn: fetchServerTime
});
return query.data;
}
다음 코드처럼 서버 API를 호출하는 Hook은 일관적으로 Query
객체를 반환하게 하면, 팀원들이 코드에 대한 예측 가능성을 높일 수 있어요.
import { useQuery } from '@tanstack/react-query';
function useUser() {
const query = useQuery({
queryKey: ['user'],
queryFn: fetchUser
});
return query;
}
function useServerTime() {
const query = useQuery({
queryKey: ['serverTime'],
queryFn: fetchServerTime
});
return query;
}
함수나 컴포넌트의 이름, 파라미터, 반환 값에 드러나지 않는 숨은 로직이 있다면, 함께 협업하는 동료들이 동작을 예측하는 데에 어려움을 겪을 수 있어요.
fetchBalance
함수의 이름과 반환 타입만을 가지고는 balance_fetched
라는 로깅이 이루어지는지 알 수 없어요. 그래서 로깅을 원하지 않는 곳에서도 로깅이 이루어질 수 있어요.
또, 로깅 로직에 오류가 발생했을 때 갑자기 계좌 잔액을 가져오는 로직이 망가질 수도 있죠.
async function fetchBalance(): Promise<number> {
const balance = await http.get<number>("...");
logging.log("balance_fetched");
return balance;
}