Skip to content

관련 없는 정보를 함께 두지 않기

관련 없는 정보를 함께 두면 코드의 의도가 모호해집니다. 관련 없는 정보는 적절히 분리하여 코드의 의도를 명확하게 합니다.

좋지 않은 예시

tsx
// hook
export const useProductSaleSection = (productId: number, userId: number) => {
  const { data: product } = useQuery(productQuery.detail(productId));
  const { data: enrollment } = useQuery(enrollmentQuery.enrollment(userId));

  const isOnSale = getIsOnSale(product);
  const isEnrolled = getIsEnrolled(product, enrollment);
  const salePrice = getSalePrice(product);

  return { product, isOnSale, salePrice, isEnrolled };
};

// component
interface SaleSectionProps {
  productId: number;
  userId: number;
}

export const SaleSection = ({ productId, userId }: SaleSectionProps) => {
  const { product, isOnSale, salePrice, isEnrolled } = useProductSaleSection(
    productId,
    userId,
  );

  return (
    <div>
      <p>product: {product.name}</p>
      <p>isOnSale: {isOnSale}</p>
      <p>salePrice: {salePrice}</p>
      {isEnrolled && <p>이미 수강중인 상품입니다</p>}
    </div>
  );
};

문제

useProductSaleSection은 SaleSection에서 사용할 정보들을 모아서 반환해주고 있습니다. 즉, useProductSaleSection 목적은 UI에 의존적입니다. UI가 빠르게 변하는 프론트엔드 환경에서는 이 함수 또한 자주 변경이 필요해질 것이고 이 함수를 호출하는 모든 곳이 동시에 변경되어야 합니다. 따라서 유지보수가 어렵고 재사용이 어려워집니다.

또한, product와 enrollment 데이터를 동시에 관리하고 있기 때문에 각 데이터에 변경이
있을 때 모두 하나의 훅을 수정하게 됩니다. 이는 서로 관계없는 데이터가 한 곳에 모여 있다는
뜻으로, enrollment 로직을 수정할 때 product 관련 코드에 의도치 않은 영향을 줄 수 있습니다.

좋은 예시

tsx
// hook
const useProductSaleInfo = (productId: number) => {
  const { data: product } = useQuery(productQuery.detail(productId));
  const isOnSale = getIsOnSale(product);
  const salePrice = getSalePrice(product);
  return { isOnSale, salePrice };
};

const useIsEnrolled = (userId: number) => {
  const { data: enrollment } = useQuery(enrollmentQuery.enrollment(userId));
  const isEnrolled = getIsEnrolled(product, enrollment);
  return isEnrolled;
};

// component
interface SaleSectionProps {
  productId: number;
  userId: number;
}

export const SaleSection = ({ productId, userId }: SaleSectionProps) => {
  const { data: product } = useQuery(productQuery.detail(productId));
  const { isOnSale, salePrice } = useProductSaleInfo(productId);
  const isEnrolled = useIsEnrolled(userId);

  return (
    <div>
      <p>product: {product.name}</p>
      <p>isOnSale: {isOnSale}</p>
      <p>salePrice: {salePrice}</p>
      {isEnrolled && <p>이미 수강중인 상품입니다</p>}
    </div>
  );
};

상품의 판매 정보와 관련 있는 데이터와 수강권과 관련 있는 데이터를 분리해서 관리합니다.

이제 product 데이터 구조에 변경이 생겼을 때 어느 곳을 수정해야 할 지 명확해집니다. 그 변화에 enrollment는 더 이상 영향 받지 않습니다.

UI가 아닌 데이터의 성격을 기준으로 함수를 구성했기 때문에 함수의 책임과 의도가 더 명확해졌습니다.