원티드의 프리온보딩에서 관심사의 분리에 대해서 배우게 되었습니다.
항상 함수를 분리할 때 '어떻게, 왜, 얼마나' 분리해야할 지에 대해서 고민이고, 분리하고 나서도 썩 마음에 들지 않을 때가 많았었는데, 이때 사용할 수 있는 방법으로 값, 계산, 액션에 따라서 관심사를 나누어서 분리하는 것입니다.
<쏙쏙 들어오는 함수형 코딩> 에서 정의한 바에 의하면 데이터, 계산 , 액션을 아래와 같이 정의합니다.
1) 데이터 : 이벤트에 대한 사실. 문자열, 객체 등 단순한 값 그 자체
2) 계산 : 입력으로 얻은 출력. 순수 함수, 수학 함수 라고 부르기도 함.
3) 액션 : 외부 세계와 소통하므로 실행 시점과 횟수에 의존. 부수 효과를 일으킴
그때 보여주셨던 예시도 정규식을 활용하여 email검사하는 것이었는데, 마침 제가 짜려는 코드주엥 정규식을 활용한 방식이 있어서 해당 함수에 적용해보려고 합니다.
const handleInputChange = (value: string) => {
const regex = /^\d*(\.\d{0,2})?$/;
if (regex.test(value)) {
if (Number(value) < 0) {
return setPercent('0.00');
}
if (Number(value) > 100) {
return setPercent('100.00');
}
setPercent(value);
}
};
위 코드는 현재 입력 값을 받았을 때, 0~100이하의 소숫점 2째짜리까지 가능한 값만 입력 가능하도록 인풋값을 조정해주는 함수입니다.
이때 단순히 함수 이름도 모호하게 인풋값을 바꿔주는 놈이라는 의미로 러프하게 작성했습니다.
위 코드가 불편한 이유는 현재 계산과 액션이 섞여 있습니다.
useState의 setter의 경우에는 상태 값을 바꾸고 리렌더링을 하는, 즉 외부 세계와 소통하는 함수입니다.(액션)
반면에 단순히 정규식 조건에 부합하는 지 테스트하는 함수는 입력값만 동일하다면 출력 값이 동일한 순수 함수입니다. (계산)
따라서 해당 정규식을 사용하는 부분을 따로 함수로 분리하고자 합니다.
export function isValidPattern(value: string, reg: RegExp) {
return reg.test(value);
}
해당 함수가 다른 곳에서도 사용될 수 있도록, 정규식도 매개변수로 받도록 하였습니다.
const FLOAT_POINT_TWO = /^\d*(\.\d{0,2})?$/;
const setValidInput = (value: string) => {
if (!isValidPattern(value, FLOAT_POINT_TWO)) return;
if (Number(value) < 0) {
return setPercent('0');
}
if (Number(value) > 100) {
return setPercent('100.00');
}
setPercent(value);
};
이제 소수점 2째 자리까의 실수가 아니면 return되고, 0 이하면 0 , 0이상이면 100이 입력되도록 변경하였습니다.
함수명은 가능한 인풋을 입력하도록 하는 녀석이니깐, setValidInput으로 명명했습니다..
또한 상수값의 경우도 소숫점 둘째자리의 실수라는 뜻으로 FLOAT_POINT_TWO라고 명명했습니다.