로깅 함수 분리하기
로깅함수는 훅이나 다른 함수에 같은 위계로 추상화하지 않습니다.
좋지 않은 예시
tsx
// hook
export const usePurchaseProduct = ({ productId }: { productId: number }) => {
const { mutate } = useMutation(productQuery.purchase());
const product = useProductDetail(productId);
const purchaseProduct = () => {
sendCPLog('scc_button_click', { productId });
mutate(product);
};
return purchaseProduct;
};
// component
export const PurchaseButton = ({ productId }: { productId: number }) => {
const purchaseProduct = usePurchaseProduct(productId);
const handlePurchaseButtonClick = () => {
purchaseProduct();
};
return <button onClick={handlePurchaseButtonClick}>구매하기</button>;
};문제
로깅과 비즈니스 로직의 혼재
usePurchaseProduct는 상품을 구매하는 비즈니스 로직을 담당하는 훅으로, 로깅과는 다른 책임을 가집니다. 즉, usePurchaseProduct 비즈니스적 맥락을 담고 있고 로깅은 사용자의 인터렉션에 따른 로그 수집에 대한 책임을 가집니다.
이 구조에서는 다음과 같은 문제가 생깁니다.
필요한 데이터가 다름: 구매 로직은
product전체가 필요하지만, 로깅은productId만 있으면 됩니다. 관심사가 다르면 필요한 데이터도 다르고, 변경 이유도 달라집니다. 로깅 스펙이 바뀔 때마다 비즈니스 로직 훅을 수정해야 하는 상황이 생깁니다공통 로직 사용의 오류 가능성: 만약 다른 지면에서 구매 로직이 필요하다면, 그때도 동일한 로깅이 필요할지 알 수 없습니다. 다른 로그가 필요할 경우 해당 훅을 수정해야 합니다. 이는 훅의 재사용성을 떨어뜨립니다.
좋은 예시
tsx
// hook
export const usePurchaseProduct = ({ productId }: { productId: number }) => {
const { mutate } = useMutation(productQuery.purchase());
const purchaseProduct = () => {
mutate(product);
};
return purchaseProduct;
};
// component
export const PurchaseButton = ({ productId }: { productId: number }) => {
const purchaseProduct = usePurchaseProduct(productId);
const handlePurchaseButtonClick = () => {
purchaseProduct(productId);
sendCPLog('scc_button_click', { productId });
};
return <button onClick={handlePurchaseButtonClick}>구매하기</button>;
};훅은 비즈니스 로직만 담당하고, 로깅은 컴포넌트의 이벤트 핸들러에서 호출합니다.
