interView
리팩토링 이전 문제점 진단
디렉토리 구조
📦Admin
┣ 📂hooks
┣ 📂Template
┣ 📜AddQuestionItem.tsx
┣ 📜AddQuestionListView.tsx
┗ 📜AddTextInput.tsx
AMDIN 페이지 내에 존재하여 ADMIN 컴포넌트에 위치시켰습니다.
초기에 작성한 본인조차 의도를 파악하지 못하였습니다.
전체적인 코드 문제
하나의 컴포넌트가 너무 많은 관심사를 가지고 있다.
컴포넌트의 명칭이 의미를 파악하기 힘들다.
컴포넌트의 추상 부재
절차적인 코드
매직넘버
네이밍 문제
관리자가 제공하는 카테고리별 질문 보여주기
interViewListView : 전체 레이아웃
interViewListItem
선택 질문 하단 플레이리스트에 추가
ControlMenu
[하단 컴포넌트
]
상단에서 선택한 목록 + 유저가 추가한 목록 보여주기
AddQuestionList
AddQuestionItem
유저가 원하는 질문 추가
AddTextInput
리팩토링 전략
[네이밍 변경
]
레이아웃 : ExpectedQuestionLayout
관리자가 채택한 예상 질문 : ExpectedQuestionSelector
예상 질문 리스트 : ExpectedQuestionList
예상 질문 : ExpectedQuestionItem
예상 질문 카테고리 : QuestionSelector
유저가 조합한 예상 질문 리스트 : UserQuestionPlayList
유저가 조합한 질문 : UserQuestionPlayListItem
유저가 질문 추가 : QuestionAdder
액션 버튼 : ActionBtns
[관심사 분리
]
직접적으로 관리하던 CheckList 관련 상태를 커스텀훅으로 분리
유저가 선택한 InterviewQuestion 상태를 관련 리덕스 추가
유저가 선택한 예상 질문 관련 상태 커스텀훅으로 관리
ExpectedQuestionList를 분리
ExpectedQuestionLayOut을 추가하여 전체 구성 관리
ActionBtns를 추가하여 버튼을 관리
QuestionSelector 추가하여 유저가 선택하는 질문 카테고리를 관련
한눈에 살펴봐도 코드의 가독성은 떨어지고 유지보수의 효율도 좋지 못한 코드의 형태였습니다.
리팩토링 적용 후 코드
Layout
import React from "react";
import styled from "styled-components";
import { ColBox, FlexBox, ScrollBar } from "@/styles/GlobalStyle";
import UserQuestionPlayList from "./PlayList/UserQuestionPlayList";
import ExpectedQuestionSelector from "./ExpectedQuestion/ExpectedQuestionSelector";
const ExpectedQuestionLayout = () => {
return (
<InterViewListViewStyle>
<ExplanationContent />
<SwitchContainer>
<LeftContainer>
<ExpectedQuestionSelector />
</LeftContainer>
<UserQuestionPlayList />
</SwitchContainer>
</InterViewListViewStyle>
);
};
기존 로직에 있던 렌더링 부분을 관심사에 별로 분류하여 컴포넌트를 분리 하였습니다.
ExplanationContent : 설명을 담당
ExpectedQuestionSelector : 유저가 선택하는 예상 질문 관련 담당
UserQuestionPlayList : 유저가 인터뷰 면접시 조합하여 만드는 질문 담당
유저가 선택한 예상 질문
const ExpectedQuestionSelector = () => {
const { selectedType, dispatchSelectedType, dispatchSelectedQuestions } =
useEUserQuestionManager();
const { interViewQuestionList, dispatchRemoveQuestions } =
useExpectedQuestionManager();
const { checkList, handleAllCheck, handleCheckList, isAllCheck } =
useCheckList(interViewQuestionList);
return (
<Card size={{ height: "450px", width: "100%", flex: "Col" }}>
<QuestionSelector
selectedType={selectedType}
onChange={dispatchSelectedType}
/>
<ExpectedQuestionList
questions={interViewQuestionList}
isAllCheck={isAllCheck}
handleCheckList={handleCheckList}
></ExpectedQuestionList>
<ActionBtns
checkList={checkList}
onAdd={dispatchSelectedQuestions}
selectedType={selectedType}
isAllChecked={isAllCheck}
onRemove={dispatchRemoveQuestions}
onToggleAll={handleAllCheck}
questions={interViewQuestionList}
></ActionBtns>
</Card>
);
};
export default ExpectedQuestionSelector;
커스텀훅을 사용하여 비즈니스 로직을 관심 별로 정리 해줬습니다.
useEUserQuestionManager() : 서버로 부터 제공받는 질문 리덕스 관리
useExpectedQuestionManager() : 유저가 설정하는 질문 리덕스 관리
useCheckList : 체크리스트에 대한 관리 위임 커스텀훅
유저가 조합한 예상 질문리스트
const UserQuestionPlayList = () => {
const { userQuestion, handleRemoveText, handleAddText, roleAction, Modal } =
useExpetedPlayListLogic();
return (
<AddQuestionListViewStyle>
<Card size={{ height: "450px", width: "100%", flex: "Col" }}>
<Container>
{userQuestion &&
userQuestion.map((question, idx) => (
<UserQuestionPlayListItems
key={idx}
item={question}
index={idx}
handleRemoveText={handleRemoveText}
></UserQuestionPlayListItems>
))}
</Container>
<QuestionAdder
handleAddQuestion={handleAddText}
handleCancelQuestion={roleAction}
/>
</Card>
<Modal />
</AddQuestionListViewStyle>
);
};
비즈니스 로직을 커스텀훅으로 분리 하여 코드의 가독성을 높였습니다.
뷰 라는 관심사의 컴포넌트 책임만을 전담
리팩토링 적용후 디렉토리 구조
📦InterViewQuestion
┣ 📂ExpectedQuestion
┃ ┣ 📜ActionBtns.tsx
┃ ┣ 📜ExpectedQuestionList.tsx
┃ ┣ 📜ExpectedQuestionListItem.tsx
┃ ┣ 📜ExpectedQuestionSelector.tsx
┃ ┗ 📜QuestionSelector.tsx
┣ 📂hooks
┃ ┣ 📜useEUserQuestionManager.ts
┃ ┣ 📜useExpectedPlayListLogic.ts
┃ ┗ 📜useExpectedQuestionManager.ts
┣ 📂PlayList
┃ ┣ 📜QuestionAdder.tsx
┃ ┣ 📜UserQuestionPlayList.tsx
┃ ┗ 📜UserQuestionPlayListItems.tsx
┗ 📜ExpectedQuestionLayout.tsx
Last updated