랜덤 문자열 생성 함수 리팩토링 - 가독성과 확장성을 높이는 방법 🛠️
간단한 랜덤 문자열 생성 함수가 필요해 빠르게 코드를 작성했다가, 좀 더 유지보수가 쉽고 깔끔한 코드로 개선하고 싶다는 생각이 들었다. 랜덤한 영문 소문자와 숫자를 각각 뽑아내는 기능을 요구사항으로 두고 리팩토링을 시작했다
처음 버전
처음 작성한 코드는 기능적인 문제 없이 잘 동작했다. generateRandomString과 generateRandomNumberString 두 개의 함수를 만들어 각기 다른 문자셋을 관리하는 방식이었다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const generateRandomString = (length) => {
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
let result = '';
for (let i = 0; i < length; i++) {
result += characters.charAt(Math.floor(Math.random() * characters.length));
}
return result;
};
const generateRandomNumberString = (length) => {
const characters = '0123456789';
let result = '';
for (let i = 0; i < length; i++) {
result += characters.charAt(Math.floor(Math.random() * characters.length));
}
return result;
};
하지만 코드를 보면서 아쉬움을 느꼈다. 두 함수가 거의 동일한 로직을 반복하고 있어, ‘중복 코드’가 눈에 띄었다. 이대로 두면 나중에 다른 종류의 랜덤 문자열(예: 특수문자 포함)이 필요해질 경우, 새로운 함수를 또 만들어야 할 것이다.
바뀐 버전
이러한 문제를 해결하기 위해 객체를 활용해 문자셋을 관리하는 방식으로 코드를 개선했다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
const dictionary = {
'a-z': 'abcdefghijklmnopqrstuvwxyz',
'0-9': '0123456789',
};
const generateRandomString = (type: 'a-z' | '0-9', length = 4) => {
const characters = dictionary[type];
let result = '';
for (let i = 0; i < length; i++) {
result += characters.charAt(Math.floor(Math.random() * characters.length));
}
return result;
};
위와 같이 dictionary라는 객체를 만들어 문자셋을 저장하고, 함수는 이 객체에서 원하는 타입의 문자셋을 가져와 사용하도록 변경했다. 추가적으로 length = 4로 default 값을 지정해주면서, length의 type을 any에서 number로 명확하게 지정해주는 효과도 얻었다.
리팩토링 후 얻은 네 가지 이점 👍
이번 리팩토링을 통해 얻은 가장 큰 이점은 다음과 같다.
코드 중복 제거: 이제 하나의 함수로 여러 종류의 랜덤 문자열을 생성할 수 있다. 조건문으로 분기하는 대신, 객체의 키(key)를 통해 원하는 값을 바로 가져오는 방식이 훨씬 깔끔하다.
가독성 향상:
a-z,0-9와 같은 직관적인 키 이름 덕분에 어떤 문자셋을 사용하는지 코드만 봐도 바로 이해할 수 있다.- 뛰어난 확장성: 나중에 특수문자나 대문자 등 새로운 타입의 랜덤 문자열이 필요해도,
dictionary객체에 새로운 키-값 쌍만 추가해주면 된다. 기존 함수 로직은 전혀 수정할 필요가 없다. - 타입 안정성 확보:
length = 4와 같이 매개변수에 기본값을 설정함으로써, 함수 호출 시length인자를 생략할 수 있게 되었다. 더불어length의 타입이any에서number로 명확하게 지정되어 함수의 안정성이 향상되는 이점도 얻었다.
추가로 생각해볼 점
1
'a-z' | '0-9'
대신
1
keyof typeof dictionary
를 사용하면 어떨까?
1
2
3
4
5
6
7
8
9
10
11
12
13
const dictionary = {
'a-z': 'abcdefghijklmnopqrstuvwxyz',
'0-9': '0123456789',
};
const generateRandomString = (type: keyof typeof dictionary, length = 4) => {
const characters = dictionary[type];
let result = '';
for (let i = 0; i < length; i++) {
result += characters.charAt(Math.floor(Math.random() * characters.length));
}
return result;
};
이렇게 작성하면 새로운 문자열 셋이 추가되더라도, generateRandomString 함수를 수정할 필요가 없어진다. 따라서 원래 방식처럼 타입을 따로 쓰는 것보다 유지보수가 쉬워진다.