Assignment 4 과제 후기 글입니다.
리팩토링 레파지토리
이번 과제는 평소 과제와 달리 급하게 개발된 프로젝트를 코드 리뷰하는 과제입니다. 동시에 확장성과 재사용 가능한 코드를 고려하여 리팩토링도 진행해봤습니다.
코드 리뷰 내용은 따로 정리했기 때문에 어떻게 코드 리뷰를 진행했는지 작성하려 합니다.
사실 같은 직군간 협업은 프리 온보딩 들어와서 거의 처음 해봤기 때문에 코드 리뷰를 제대로 해본 경험이 없습니다. 따라서 어떻게 진행해야 하나 고민하다 코드를 분석해보며 아쉬웠던 점, 개선하면 좋을 것 같은 점들을 바로바로 적어가며 분석해봤습니다.
코드 분석 방법
프로젝트의 시작인index.js
,app.js
부터router
구현 로직을 보고 마치 DFS + BFS 알고리즘처럼 모든 컴포넌트들을 분석합니다.
제가 봐도 개선이 필요하다고 알 수 있었던 것들을 정리해봤습니다.
대놓고 제목이라고 되어있는 곳도 div 태그를 이용한 마크업 구조입니다.
검색 결과를 보여주는 메인 컴포넌트이기 때문에 main 태그
를 사용했고 검색 리스트들을 ul, li 태그
를 이용해 마크업 했습니다.
또 img 태그
에 alt
를 의미 있게 작성하고, 세부 내용을 section
으로 감싸고 제목 부분을 h3 태그
를 이용해 마크업 했습니다.
이번 코드 리뷰의 키워드 중 하나는 확장성 고려입니다. 따라서 지금 당장은 보기 불편하지 않고 오히려 더 나은 구조이지만 확장성을 고려해 잘게 나누는데 초점을 맞춰 리팩토링했습니다.
store 폴더 안에 store 생성 로직
, reducers 로직
, 비동기 네트워크 통신 로직
이 모두 한 폴더 안에 담겨져 있었습니다. 확장성을 고려해 이 세 가지 로직을 모두 분리했습니다.
store 폴더
reduxToolkit
의 configureStore
를 이용해 store 생성, middleware 설정, devTools 관리를 한 번에 구현했습니다.
const store = configureStore({
reducer: rootReducer,
middleware: [sagaMiddleware],
devTools: process.env.NODE_ENV !== "production",
});
reducers 폴더
reducer는 이미 redux toolkit
의 createSlice
를 이용해 굉장히 깔끔하게 구현이 돼있었습니다.(아마도..?) redcuer 밑에 구현된 비동기 네트워크 통신 부분만 따로 분리했습니다.
다만 initialState
를 밖에서 구현하는 걸 선호하기 때문에 밖에서 구현했고, 실패 시 상태 설정이 누락되어 있어 추가했습니다.
const initialState = {
items: [],
totalItems: 0,
startIndex: 0,
status: STATUS.Idle,
error: null
}
const booksSlice = createSlice({
name: 'books',
initialState,
reducers: {
...
getItemsFailure(state, action) {
state.status = STATUS.Failure
state.error = action.payload
}
}
})
비동기 네트워크 통신 로직 ( sagas 폴더 )
export const fetchBooks =
(search, startIndex = 0) =>
async (dispatch) => {
try {
dispatch(getItemsStart(startIndex));
const response = await getBooks(search, startIndex);
const data = await response.json();
dispatch(getItemsSuccess({ ...data, startIndex }));
} catch (error) {
dispatch(getItemsFailure(error));
}
};
굉장히 익숙한 구조를 보고 비동기 네트워크 통신을 하는 로직임을 알아차렸습니다. 사실 redux-thunk
와 유사한 코드이지만, 역시 확장성을 고려해 다양한 effect
가 있는 redux-saga
로 리팩토링하기로 결정했습니다.
// redux-saga로 구현
function* fetchBooksSaga(action) {
const { search, startIndex } = action.payload;
try {
const response = yield call(fetchApi.fetchBooksAPI, search, startIndex);
yield put({
type: getItemsSuccess.type,
payload: { ...response.data, startIndex },
});
} catch (e) {
console.log(e);
yield put({
type: getItemsFailure.type,
payload: e,
});
}
}
사실 리액트에 대해 남의 코드를 보고 리뷰할 수준이 안된다고 생각돼서 내가 생각하는 게 맞는지 틀린 지 정확히 판단이 가지 않았습니다. 하지만 코드 리뷰라는 게 꼭 정답을 짚어야 코드 리뷰가 아니듯, 의견을 내는 방식으로 코드 리뷰를 진행했습니다.
코드 리뷰를 하기 위해 코드를 분석하다 보니 어느 순간 왜 이렇게 코드를 구현했는지 이해를 하고 수긍하고 있었습니다. 코드 분석을 한 후 리뷰를 하는 과정을 거치면 더 좋은 코드 리뷰를 할 수 있을 거라 생각됩니다.
CSS는 처음 보는 구조라 검색을 해봤습니다. 검색 결과 tailwind
css였고 대충 공식 문서를 보고 사용법을 봤는데 딱히 개선할 부분은 보이지 않아 CSS는 큰 신경을 쓰지 않았습니다.
코드 리뷰 내용이 맞는지 확인하기 위해 오히려 더 공부를 많이 했습니다. 이 태그의 사용법이 맞는지, 커스텀 훅을 어떻게 하면 더 잘 구현하는지, redux-toolkit
의 사용법 등 남의 코드를 리뷰해 주려다 제가 더 성장한 느낌이 들었습니다.
서비스 기업의 기업 문화 중 코드 리뷰를 굉장히 중요시하는 기업이 많은 걸로 알고 있습니다. 비슷한 예제로 실제로 코드 리뷰를 경험할 수 있어 많은 도움이 된 것 같습니다.