현재 진행하고 있는 co-MusicPlayer 프로젝트이다.
Spring boot와의 협업이 처음이라 BE에서 열어둔 EndPoint로 요청을 보내고 응답을 정상적으로 받는지 확인
하는 컴포넌트를 작성하였다.
//search.tsx
import axios from 'axios';
const GetData = () => {
const [searchData, setSearchData] = useState('');
const getSearch = await() => {
const response = axios.get('/api/hello');
setSearchData((prev) => response.data);
}
return (
<>
<div>
백엔드에서 가져온 데이터입니다 :
{searchData ? searchData : '데이터 없음'}
</div>
<ToggleBtn onClick={getSearch}>search</ToggleBtn>
</>
);
};
export default GetData;
코드를 복기하면 느낀 문제점은 아래와 같다.
위의 문제점들을 고려
하여 아래와 같이 리팩터링을 진행
하였다.
우선 하드코딩 되어있는 값들을 변경에 취약하지 않도록 소프트 코딩하였다.
// ./utils/contant/apiConstant.ts
/* Interfaces */
interface endPoint {
[key: string]: string;
}
interface error {
[key: string]: string;
}
interface api {
[key: string]: endPoint | error;
}
/* CONSTANTS */
const END_POINT: endPoint = Object.freeze({
HELLO: '/api/hello',
});
const ERROR: error = Object.freeze({
ENONT: 'ENOENT',
ENONT_MESSAGE: 'Unusable API EndPoint',
PROTOCOL_MESSAGE: 'Protocol Error',
});
const API: api = Object.freeze({
END_POINT: END_POINT,
ERROR: ERROR,
});
export default API;
TS의 interface를 이용한 Type 안정성 확보.
참조값인 Object type은 변화에 취약한 데이터 타입이다.
따라서, const
키워드로 메모리의 변수 영역
을 immutable 영역으로 고정시킨 뒤, Object.freeze
를 이용해 Object의 데이터 영역
. 즉, key와 value의 변수 영역을 참조하고 있는 메모리 공간(데이터 영역)을 immutable하게 고정
한다.
또한, Object.freeze의 depth는 1까지만 적용이 되기 때문에 값을 immutable화 하는 과정을 depth별로 진행하였다. 해당 부분은 nested Obejct의 구조의 depth가 깊어질수록 선언에 어려움이 있어 여기까지 글을 쓰고 해결책을 1시간 정도 고민하고 찾다가 다시 돌아왔다. (추후 포스팅 예정)
import axios from 'axios';
import API from '../constants/apiConstant';
const sendGetRequest = async (END_POINT: string) => {
const { ERROR } = API;
try {
const searchResponse = await axios.get(END_POINT);
const { data } = searchResponse;
return data;
} catch (error) {
const ErrorType = error as protocolError;
if (ErrorType.code === ERROR.ENONT) throw new Error(ERROR.ENONT_MESSAGE);
throw new Error(ERROR.PROTOCOL_MESSAGE);
}
};
export default sendGetRequest;
interface protocolError {
code: string;
message: string;
}
해당 함수는 BE와 소통하는 과정에서 반복적으로 사용될 함수라고 판단이 되었다. 이전 코드는 HTTP 통신을 진행하는 Endpoint가 함수 내부
에 있기 때문에 의존성이 발생
한다고 판단하였다. 따라서, 해당 부분을 함수 외부로 빼내어, 이를 매개변수로 받도록 함수를 작성하였다.
물론, 현재 위 함수의 한계는 명확
하다.
오직 get 메서드만을 처리
하고 있기 때문이다.
따라서, 이후 리팩터링 과정은 메서드를 받는 인자를 추가
하여 이에 따른 올바른 요청을 진행하고, 결과를 return하는 함수를 작성하는 방향으로 진행할 것이다.
//search.tsx
import { useState } from 'react';
import sendGetRequest from './utils/req/sendGet';
import API from './utils/constants/apiConstant';
const Search = () => {
const [searchData, setSearchData] = useState('');
const {
END_POINT: { HELLO },
} = API;
const getSearch = async () => {
const response = await sendGetRequest(HELLO);
setSearchData((prev) => response);
};
return (
<>
<div>
백엔드에서 가져온 데이터입니다 :
{searchData ? searchData : '데이터 없음'}
</div>
<ToggleBtn onClick={getSearch}>getSearch</ToggleBtn>
</>
);
};
search.tsx의 코드는 크게 변하지 않았지만, 코드의 안정성, 확장성, 재사용성 및 유지보수성은 올랐다는 것을 느낄 수 있었다.
이전까지 잘 지키지 않았던 자체적 리팩터링 및 코드리뷰가 점점 익숙해지는 과정인 것 같다.