코드 리뷰를 통해 개발자들은 성장하고 새로운 것을 더 알아가기를 원합니다. 하지만 코드 리뷰를 해주는 사람을 찾기는 쉽지 않은 게 현실입니다. 코드 리뷰를 진행해 줄 리뷰이 와 리뷰어를 연결해 주면 좋겠다는 생각 프로젝트를 시작했습니다.
신경호 |
이의현 |
Frontend
Cloud
CI
Others
---❓ Why choose a skill?
TypeScript
-
JavaScript를 사용하는 것보다 TypeScript를 사용하는 것이 오류 발생 확률을 15%를 줄여준다고 합니다. TypeScript를 사용함으로써 타입을 통한 가독성을 높이고 휴먼에러를 최소한으로 줄여 안전성과 효율성을 높이기 위해 선택했습니다.
-
백엔드 데이터 모델과의 타입을 일치시키기 위해 선택했습니다.
NextJS
- React는 동적으로 페이지가 렌더링되기 때문에 초기 로드 시 검색 엔진 크롤러가 인식하지 못한다는 단점을 가지고 있습니다. SEO를 충족시키고 초기 렌더링이 빠른 특성을 이용해 사용자 경험을 향상시키고자 NextJS를 선택했습니다.
ReactQuery
-
클라이언트와 서버의 데이터를 분리하기 위함이였습니다. 기존에 서버 데이터를 상태관리로 관리하는 것은 적합하지 않았습니다. 클라이언트 와 서버의 데이터를 분리함으로써 관심사 분리를 할 수 있기에 선택했습니다.
-
캐싱처리로 API 콜을 줄이기 위함이였습니다. ReactQuery는 데이터를 캐싱하여 중복 요청을 줄이기 때문에, 서버와의 상호작용을 줄일 수 있습니다. 이를 통해 서버 측 부하를 줄이고 애플리케이션 성능을 향상시킬 수 있기 때문에 선택했습니다.
Recoil
- 상태관리를 정할 때 redux 와 recoil 중 어떤걸 선택할지 고민을 했습니다. 회의를 하면서 전역 상태관리로서 관리할 데이터가 별로 없다고 판단해서 recoil을 선택하게 됬습니다. redux는 작은 기능이라도 Boilerplate code가 많지만 recoil 같은 경우에는 redux와 동작 방식은 비슷하지만 Boilerplate code가 적고 간단해서 선택했습니다.
TailWind
- CSS에 대한 코드량을 줄이고 생산성을 높이기 위해 선택했습니다.
MSW
- 프론트엔드 개발은 백엔드 API와의 의존성이 있는 영역입니다. 백엔드 API 개발여부에 관한 의존성을 낮추고 완성되지 않는 상태라도 개발을 진행하기 위해서 MSW 라이브러리를 선택했습니다.
🖱 Login strategy
로그인은 깃허브 소셜 로그인만 가능하도록 되어 있으며 인증은 JWT 토큰을 사용했습니다. 토큰 정보는 세션 스토리지에 저장하고 관리하며 axios 인스턴스를 사용했으며 엑세스 토큰과 리프레시 토큰 로직을 interceptors를 사용해서 통합적으로 관리했습니다.
const instance: AxiosInstance = axios.create({
baseURL: 'http://localhost:3000',
headers: {
'Content-Type': 'application/json',
},
withCredentials: false,
timeout: 30000,
});
instance.interceptors.request.use(
(config) => {
const accessToken = sessionStorage.getItem('accessToken');
if (accessToken) {
config.headers.Authorization = `Bearer ${accessToken}`;
}
return config;
},
(error) => {
return Promise.reject(error);
},
);
instance.interceptors.response.use(
(response) => response,
async (error: AxiosError) => {
if (error.response?.status === 401) {
try {
deleteAccessTokenInStorage();
const refreshToken = getRefreshTokenInStorage();
const refreshResponse = await axios.post(
`${process.env.NEXT_PUBLIC_BACK_API}/auth/refresh`,
{
withCredentials: true,
},
{
headers: { Authorization: `Bearer ${refreshToken}` },
},
);
setAccessTokenInStorage(refreshResponse.data.accessToken);
setRefreshTokenInStorage(refreshResponse.data.refreshToken);
const config = error.config;
if (!config) {
return Promise.reject(error);
}
return instance.request(config);
} catch (err) {
deleteRefreshTokenInStorage();
window.location.href = '/induceLogin';
}
} else {
return Promise.reject(error);
}
},
);⌨ Quill Editor 적용
유저가 리뷰어에게 리뷰를 신청할 때 사용자 경험을 향상시키기 위해 Quill Editor라이브러리를 사용해서 구현했습니다. 통합적인 form 관리를 위해 react hook form라이브러리를 접목해서 사용했으며 DOM API를 사용해 글자수 제한 처리를 구현했습니다.
const editorRef = useRef < ReactQuill > null;
function ReviewEditor({ setError, setValue, getValue, trigger, editorRef }: IRegisterType) {
const modules = useMemo(() => editorModule, []);
const editorContentChange = (content: string) => {
if (editorRef.current) {
const getLength = editorRef.current.unprivilegedEditor?.getText().length;
if (getLength && getLength - 1 <= EDITORMAX) {
if (content === '<p><br></p>') {
setValue('content', '');
} else {
setValue('content', content);
}
}
}
trigger('content');
};
const editorBlurHandler = (e: ReactQuill.Range) => {
if (!e?.index) {
setError('content', { type: 'required', message: '필수 사항입니다.' });
}
};
const editorContentLength = (content: number) => {
return content > EDITORMAX ? EDITORMAX : content;
};
return (
<div>
<QuillEditor
forwardedRef={editorRef}
value={getValue('content')}
onChange={(e) => editorContentChange(e)}
placeholder="리뷰 받고싶은 내용을 입력해주세요. 최대 500글자까지 작성 가능합니다."
modules={modules}
formats={formats}
theme="snow"
onBlur={editorBlurHandler}
/>
<p className="flex justify-end w-full pr-3">
{editorRef.current && editorRef.current.unprivilegedEditor
? editorContentLength(editorRef.current.unprivilegedEditor.getText().length - 1)
: 0}
/ {EDITORMAX} 자
</p>
</div>
);
}Branch Convention
-
branch 생성은 다음과 같은 규칙을 따른다.
ex) BranchName: "feature/{#issue_num}" -
스프린트 주기에는 main이 아닌 develop 브랜치에 개발한다.
-
배포시점엔 develop에서 main으로 일반 머지를 진행한다.
-
매번 코드리뷰를 진행하며 코드리뷰가 완료되면 develop branch에 스쿼시 머지를 진행한다.
Commit Convention
커밋 컨벤션은 "type: 설명" 형식으로 한다. type은 아래와 같다.
- feat: 새로운 기능 추가
- fix: 버그 수정
- docs: 문서 관련
- style: 스타일 변경 (포매팅 수정, 들여쓰기 추가 등)
- refactor: 코드 리팩터링
- test: 테스트 관련 코드
- build: 빌드 관련 파일 수정
- ci: ci 설정 파일 수정
- chore: 위에 해당하지 않는 애매하거나 자잘한 수정