프로젝트 내 사용되지 않고 있는 파일들(번들에 포함되지 않는 파일들)을 검출하여
레거시 코드를 정리한 경험을 공유합니다.
npm: esbuild-plugin-unused-modules
Data Masking은 GraphQL 언어를 개발한 facebook에서 GraphqlQL의 철학을 담은 데이터 관리 라이브러리인 relay에서 thinking-in-relay 에 언급하고 있는 개념으로, 적용 시 컴포넌트의 데이터 의존성을 캡슐화하여 컴포넌트 내부에서는 자신이 사용하고 있는 데이터에만 관심사를 가지고 부모 컴포넌트와 자식 컴포넌트에는 어떤 데이터를 사용하고 있는지 숨김(캡슐화)으로써 다른 컴포넌트와의 데이터 의존성을 느슨하게 가져갈 수 있게됩니다.
GraphQL 진영에서 클라이언트의 데이터 관리를 위한 라이브러리로 크게 Apollo와 Relay가 존재합니다. 많은 특징과 차이점이 존재하겠지만, 이 중에서도 가장 큰 차이점이라고 볼 수 있는 점은 바로 Data Masking을 강제하느냐 아니냐 입니다. Apollo도 GraphQL 라이브러리이기 때문에 충분히 Data Masking 전략을 취하여 컴포넌트 간 데이터 의존성을 느슨하게 가져갈 수 있습니다.
그러나, Apollo는 Relay와 다르게 Data Masking 을 반드시 지켜야하도록 강제하지 않습니다. 아래 예시는 relay로 작성된 컴포넌트입니다. 각 컴포넌트는 컴포넌트와 연결된 fragment 및 query에서 정의한 데이터만 사용이 가능하도록 캡슐화하여 컴포넌트 간 데이터 의존성을 낮춰줍니다. relay에서는 CarItem 컴포넌트에서 fragment로 정의하지 않은 데이터인 wheel 필드를 참조하려고 하면 에러를 터트립니다.
const CAR = graphql`
query car($id: Int!) {
car(id: $id) {
id
color
wheel {
id
name
}
...CarItem_car
}
}
`;
const Parent = ({ carId }) => {
const data = useQuery(CAR, {
variables: { id }
});
return (
...
<CarItem .../>
)
}
const carFragment = graphql`
fragment CarItem_car on Car {
id
name
size
}
`;
const CarItem = ({
car: propCar
}) => {
const car = useFragment(carFragment, propCar);
car.wheel // 에러 발생. fragment에 정의한 데이터만 참조할 수 있음
}
위와 비교하기 위해 아래는 Apollo로 작성된 컴포넌트입니다. relay 코드와 별반 다를게 없어보이지만, relay와 다르게 이번에는 CarItem 컴포넌트에서 fragment로 정의하지 않은 데이터인 wheel 필드를 참조하려고 할 때 아무 에러도 터트리지 않습니다. 이는 Apollo에서는 Data Masking을 강제하지 않는 것으로 판단할 수 있습니다.
const CAR = gql`
query car($id: Int!) {
car(id: $id) {
id
color
wheel {
id
name
}
...CarItem_car
}
}
`;
const Parent = ({ carId }) => {
const data = useQuery(CAR, {
variables: { id }
});
return (
...
<CarItem .../>
)
}
const carFragment = gql`
fragment CarItem_car on Car {
id
name
size
}
`;
const CarItem = ({
car: propCar
}) => {
car.wheel // 참조 가능. 부모 컴포넌트에서 호출한 query에 데이터가 포함되어 있기 때문.
}