
회원가입 화면에서 입력 필드의 유효성을 검증해야 했다. 이를 위해 중복 코드 없이 재사용 가능한 방식으로 유효성 검사를 구현하고자 했다.
유효성 검증을 각각의 필드에서 개별적으로 수행하여 코드가 중복되고 관리가 어려울 수 있어서 고민을 많이 하고 구현했다.
1) 유효성 검사 로직의 추출과 정리
Validator 구조체로 분리하기로 결정했다.2) Validator 구조체 설계
validateFields 메서드에서 모든 필드를 한꺼번에 검사할 수 있도록 설계했다.isValidId, isValidPassword, isValidEmail, isValidPhone)로 캡슐화했다.3) 정규식 활용
NSPredicate를 활용해 정규식을 적용했다.4) 뷰컨트롤러와의 연동
SignupViewController에서 Validator를 호출하여 사용자가 입력한 값의 유효성을 검사했다.Validator 구조체
struct Validator {
func validateFields(id: String?, password: String?, email: String?, phone: String?) -> (Bool, String) {
if let id = id, isValidId(id) == false {
return (false, "아이디는 영어와 숫자 조합이어야 합니다.")
}
if let password = password, isValidPassword(password) == false {
return (false, "비밀번호는 영어, 숫자 포함 8자 이상이어야 합니다.")
}
if let email = email, isValidEmail(email) == false {
return (false, "유효하지 않은 이메일 형식입니다.")
}
if let phone = phone, isValidPhone(phone) == false {
return (false, "휴대폰 번호는 010으로 시작해야 합니다.")
}
return (true, "유효성 검사를 통과했습니다.")
}
private func isValidId(_ id: String) -> Bool {
let regex = "^(?=.*[A-Za-z])(?=.*\\d)[A-Za-z\\d]{1,}$"
return NSPredicate(format: "SELF MATCHES %@", regex).evaluate(with: id)
}
private func isValidPassword(_ password: String) -> Bool {
let regex = "^(?=.*[A-Za-z])(?=.*\\d)[A-Za-z\\d@$!%*?&#]{8,}$"
return NSPredicate(format: "SELF MATCHES %@", regex).evaluate(with: password)
}
private func isValidEmail(_ email: String) -> Bool {
let regex = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}"
return NSPredicate(format: "SELF MATCHES %@", regex).evaluate(with: email)
}
private func isValidPhone(_ phone: String) -> Bool {
let regex = "^010\\d{8}$"
return NSPredicate(format: "SELF MATCHES %@", regex).evaluate(with: phone)
}
}
SignupViewController
@objc
private func signup() {
guard let id = signupView.idField.text,
let password = signupView.passwordField.text,
let email = signupView.emailField.text,
let phone = signupView.phoneField.text else {
showAlert(message: "모든 필드를 입력해 주세요.")
return
}
let (isValid, message) = validator.validateFields(id: id, password: password, email: email, phone: phone)
if isValid {
showAlert(message: "회원가입이 완료되었습니다.")
} else {
showAlert(message: message)
}
}
구조체 활용: Validator 구조체를 통해 로직 분리와 재사용성을 강화할 수 있었다.
정규식의 강력함: 각 필드의 유효성 조건을 간결하고 명확하게 정의할 수 있었다.
확장 가능성: 새로운 필드가 추가되어도 Validator 구조체만 수정하면 전체 유효성 검사가 가능하도록 설계할 수 있었다.
구현 과정에서 정규식을 정확히 작성하는 것이 가장 어려웠다. 초기에는 복잡한 패턴을 작성하고 이를 디버깅하는 데 많은 시간을 소요했지만, 여러 번의 테스트를 통해 정규식을 체계적으로 관리하는 방법을 터득할 수 있었다. 한 번 구조를 잡아놓으니 유지보수와 확장이 훨씬 쉬워졌다.
Validator 구조체를 독립적으로 설계한 덕분에 각 필드별로 단위 테스트를 작성하는 것이 매우 수월했다. 이를 통해 유효성 검사 로직의 안정성을 높이고, 전체적인 코드 품질을 강화할 수 있었다. 또한, 잘못된 입력값에 대한 경고 메시지를 명확히 전달하여 사용자에게 친화적인 회원가입 프로세스를 제공할 수 있었다.
무엇보다 회원가입 화면 외의 다른 화면에서도 동일한 Validator를 재사용할 수 있는 설계 덕분에, 초기 설계 단계에서의 고민과 노력이 충분히 보상받는다는 것을 느꼈다.