type Job = {
name: string;
status: "WAITING" | "COMPLETED" | "CANCELED" | "RUNNING";
};
type RunningJob = {
name: string;
status: "RUNNING";
};
// 기존
type GpuServer = {
// ...중략,
jobs: Job[];
};
const Component = () => {
const gpuServer = useAsyncHook<GpuServer>();
const runningJobName = gpuServer.jobs.find((job) => job.status === "RUNNING")?.name ?? "N/A";
const waitingJobCount = gpuServer.jobs.filter((job) => job.status === "WAITING").length;
}, 0);
return (
<div>
<span>현재 실행중인 Job: {runningJobName} </span>
<span>대기중인 Job의 개수: {waitingJobCount}개 </span>
</div>
);
};
// 변경후
type GpuServer = {
// ...중략,
runningJob: RunningJob | null;
waitingJobCount: number;
};
const Component = () => {
const gpuServer = useAsyncHook<GpuServer>();
return (
<div>
<span>현재 실행중인 Job: {gpuServer.runningJob?.name ?? "N/A"} </span>
<span>대기중인 Job의 개수: {waitingJobCount}개 </span>
</div>
);
};
runningJob)과 대기중인 Job의 개수(waitingJobCount)를 계산하였으나, 서버측에서 runningJob과 waitingJobCount를 계산하여 프론트로 보내주는 방식으로 변경되었습니다.runningJob과 waitingJobCount 계산하는 부분을 삭제하면 되니 간단한 대응이라고 생각하였으나, 실제로 변경에 대응하다보니 11개의 파일이 변경되었습니다.

runningJob과 waitingJobCount 계산하는 비즈니스 로직 모두 가지고 있습니다.runningJob과 waitingJobCount 를 필요로 하는 모든 컴포넌트에서 각각 runningJob과 waitingJobCount를 계산하고 있었기에 이를 모두 수정하여야 합니다.⇒ 역할과 책임을 구분하는 레이어가 명확하지 않아, 변경에 취약한 구조라고 결론내렸습니다.
개선방안 1. 서비스 계층을 분리하고 커스텀 훅에서 비즈니스 로직을 담당합니다.

개선방안 2. 상태관리 툴을 도입합니다.



⇒ 기존에 waitingJobCount, runningJob 을 Reducer에서 계산했다면, 사용하는 Component는 API Response가 변경되더라도 Store에서 상태를 가져오는 것은 동일하므로 아무런 변경 사항이 없었을 것입니다. 즉, 레이어를 구분한다면, 역할과 책임을 명확히 하여 변경사항이 전파되는 경계점을 쉽게 파악할 수 있을 것으로 예상됩니다.
현재 프로젝트에는 gpServer, job, member 의 3가지 도메인이 존재합니다.
최소 필수 기능은 모두 구현된 상태에서 리덕스를 전면적으로 도입하는 것은 많은 코드 수정을 불러일으키므로, 여파를 최소화 하기 위해 가장 로직이 간단한 member 부터 도입하기로 결정하였습니다.
memberSlice 의 구조도는 아래와 같습니다.


member 기능을 리덕스로 마이그레이션 중입니다
