프론트엔드 애플리케이션에서 클린 아키텍처의 유스케이스 구현 방법
2025-04-09 12:36:32클린 아키텍처란 무엇인가?
프론트엔드 애플리케이션에서 클린 아키텍처는 복잡한 코드를 정리하고 모듈화하여 유지보수를 더욱 쉽고 효율적으로 만듭니다. 클린 아키텍처는 데이터 흐름을 명확히 하고, 코드의 재사용성을 높이며, 개발자의 생산성을 향상시킵니다.
유스케이스의 정의와 역할
클린 아키텍처 방식에서는 유스케이스가 애플리케이션의 비즈니스 로직을 담당하며, 엔티티, 게이트웨이, 트랜잭션을 조율하여 특정 사용자 목표를 충족합니다. 유스케이스는 데이터 처리를 직접 반환하지 않고, 데이터를 엔티티, 게이트웨이, 셀렉터 등을 통해 뷰 유닛으로 보냅니다.
유스케이스의 구현 방식
인라인 유스케이스 구현
인라인 유스케이스는 컨트롤러 내에 간단한 함수 형태로 구현되며, 애플리케이션 오케스트레이션 로직에 집중하게 해줍니다. 다음은 기본적인 인라인 유스케이스 구현 예제입니다.
interface OrderProps {
orderId: string;
}
interface Controller {
deleteOrderButtonClicked(id: string): Promise<void>;
}
const useController = (params: { orderId: string }): Controller => {
const deleteOrderButtonClicked = async () => {};
return { deleteOrderButtonClicked };
};
export const Order: FC<OrderProps> = (props) => {
const presenter = usePresenter(props);
const controller = useController(props);
return (
<>
<button onClick={controller.deleteOrderButtonClicked}>Delete</button>
<div style={{ padding: "5px" }}>
{presenter.itemIds.map((itemId) => (
<OrderItem key={itemId} itemId={itemId} />
))}
</div>
</>
);
};
발전된 인라인 유스케이스 구현
인라인 유스케이스는 종종 복잡한 로직으로 발전하며, 이 경우 유지보수성과 테스트 용이성을 위해 추출된 형태로 변경됩니다. 아래는 발전된 인라인 유스케이스 예제입니다.
interface OrderProps {
orderId: string;
}
interface Controller {
deleteOrderButtonClicked(id: string): Promise<void>;
}
const useController = (params: { orderId: string }): Controller => {
const setItemsFilterById = useOrdersPresentationStore((state) => state.setItemsFilterById);
const resource = useOrdersResourceSelector();
const { mutateAsync: deleteOrder } = useMutation({ ...useDeleteOrderOptions(resource) });
const deleteOrderButtonClicked = async () => {
// inline usecase
setItemsFilterById(null);
await deleteOrder({ id: params.orderId });
};
return { deleteOrderButtonClicked };
};
추출된 유스케이스 구현
유스케이스 로직이 여러 곳에서 사용되거나 복잡해지면, 인라인 유스케이스를 별도의 함수 혹은 모듈로 분리하여 더욱 깔끔하고 효율적으로 관리합니다.
interface OrderProps {
orderId: string;
}
interface Controller {
deleteOrderButtonClicked(id: string): Promise<void>;
}
// extracted usecase
export const useDeleteOrderUseCase = (): { execute: (params: { orderId: string }) => Promise<void> } => {
const setItemsFilterById = useOrdersPresentationStore((state) => state.setItemsFilterById);
const resource = useOrdersResourceSelector();
const { mutateAsync: deleteOrder } = useMutation({ ...useDeleteOrderOptions(resource) });
const execute = async (params: { orderId: string }) => {
setItemsFilterById(null);
await deleteOrder({ id: params.orderId });
};
return { execute };
};
const useController = (params: { orderId: string }): Controller => {
const { execute: executeDeleteOrderUseCase } = useDeleteOrderUseCase();
const deleteOrderButtonClicked = async () => {
await executeDeleteOrderUseCase({ orderId: params.orderId });
};
return { deleteOrderButtonClicked };
};
유스케이스의 테스트 및 위치 선정
유스케이스는 외부 의존성을 모킹하여 단독으로도 테스트할 수 있으며, 다른 유닛과의 통합 테스트도 가능합니다. 유스케이스는 일반적으로 usecases 디렉토리에 위치해야 합니다.
결론
프론트엔드 애플리케이션에서 클린 아키텍처의 유스케이스를 구현함으로써, 코드를 더 명확하고 유지보수가 용이하게 만들 수 있습니다. 클린 아키텍처는 프론트엔드 개발에서 복잡성을 줄이고, 코드의 품질을 향상시키는 데에 필수적입니다.