[TIL] 파이널 프로젝트 16일차 - decoupling & UIAlertController

7과11사이·2023년 10월 29일
0

스파르타코딩클럽

목록 보기
84/90
post-thumbnail

며칠간 파이널 프로젝트 덕분에 기록의 중요성을 잊어버렸다...
3주동안 코드를 잡고 있다보니 혼자 퍼지기도, 개인적 문제가 발생하기도 했는데, 여러모로 배우는 부분이 많다.

하지만 게임처럼 일상에서 내 상태를 알려주는 알람이 있으면 얼마나 재밌을까?
적어도 어플에서만큼은 상황을 전달하는 UIAlertController에 대해 공부한 내용을 적어본다!


1. 로그인/ 회원가입 페이지 - 🚨문제 발견

담당 페이지는 로그인, 회원가입 그리고 사용자 입맛 확인 페이지.
어플을 키고 대면하는 첫 얼굴(?)이자 인증 기능을 구현해보고 싶어 지원한 화면이 이렇게 복잡해질 줄은 몰랐다.
모두 쉽게 처리하는데 나만 그런걸수도 있겠다!

유효성 검사 덕분에 주로 Login, Registration VC 그리고 DB와 소통을 담당하는 FireStoreManager에서 수정이 잦은 편이다.
기존에는 아래처럼 FireStoreManager에서 유효성 검사를 하도록 처리했다.

class FireStoreManager {
static let shared: FireStoreManager()

...
    // 전화번호 유효성 검사
func validateNumber(_ number: String) -> Bool {
        if number.isEmpty {
            print("번호가 입력이 되지 않았어요")
            return false
        } else if Int(number) == nil {
            print("번호 형식을 맞춰주세요")
            return false
        } else if number.count != 11 {
            print("번호가 짧아요")
            return false
        }
        return true
    }
    
    // 비밀번호 유효성 검사
    func validatePassword(_ password: String) -> Bool {
        let passwordCheck = "^(?=.*[A-Z])(?=.*[0-9])(?=.*[a-z]).{8}$"
        let predicate = NSPredicate(format:"SELF MATCHES %@", passwordCheck)
        return predicate.evaluate(with: password)
    }
    
...
    
}

class LoginViewController: UIViewController {

...

 @objc func loginButtonTapped() {
        print("로그인 버튼이 눌렸습니다.")
        
        let id = idTextfieldView.textfield.text!
        if FireStoreManager.shared.validateID(id) {
            print(id)
            let vc = TabBarViewController()
            vc.modalPresentationStyle = .fullScreen
            present(vc, animated: true)
        } else {
            print("불허가")
        }
    }
    
...

}

처음에는 위처럼 코드를 짰다.
FireStoreManager의 역할은 전반적 사용자 데이터 관리였는데, 유효성 검사 단계를 처리하면서 역할에 대해 다시 한번 생각하게 됐다.

편의상 FireStoreManager에 데이터 관련 코드를 작성하고 있었는데
매번 유효성 검사 단계에서 FireStoreManager을 호출하는 과정도,
해당 유효성 검사 함수들이 FireStoreManager에서 관리한다는 점이 이상하게 다가왔다.



2. Code Decoupling - 🔎 이슈 파악

Login, Registration에서 작성한 유효성 검사 함수 또한 무거워지는 상황을 마주했었다.
예를 들어 아래와 비슷한 형식으로 코드를 작성하고 있었는데,

func signIn(with email: String, password: String, completion: @escaping ((Bool) -> Void)) {
        print("=========\(password)")
        guard FireStoreManager.shared.validatePassword(password) else {
            print("비밀번호를 한번 더 확인 해주세요")
            completion(false)
            return
        }
        Auth.auth().createUser(withEmail: email, password: password) { result, error in
            if let error = error {
                print("여기가 문제인가요 유저를 생성하는데 에러가 발생했습니다. \(error.localizedDescription)")
                completion(false)
            }
            print("결과값은 아래와 같습니다 - \(result?.description)")
            completion(true)
        }
    }

사용자를 생성하는 Auth.auth().creatUser 함수는 registrationVC가,
비밀번호 유효성 검사는 FireStoreManager에서 처리를 하고 있었다.
나름 고민하고 있다 믿었지만 막상 어떻게 구현만 하자는 생각이 강해서였는지
정신 차리고 보니 역할과 책임이 모호해지는 내 코드를 마주했다.

3. Code Decoupling - 👾 적용

따라서 아래처럼 코드를 분리했다.

@objc func confirmButtonTapped() {
        print("회원가입 버튼이 눌렸습니다.")
        
        guard let id = emailTextFieldView.textfield.text, !id.isEmpty,
              let pw = pwTextFieldView.textfield.text, !pw.isEmpty,
              let number = numberTextFieldView.textfield.text, !number.isEmpty else { return }

        guard checkIdPattern(id) else {
            emailTextFieldView.showInvalidMessage()
            showAlert(type: .idError)
            return
        }
        
        guard validPasswordPattern(pw) else {
            pwTextFieldView.showInvalidMessage()
            showAlert(type: .passwordBlank)
            return
        }
        
        guard validateNumberPattern(number) else {
            numberTextFieldView.showInvalidMessage()
            return
        }
        
        FireStoreManager.shared.signIn(with: id, password: pw) { success in
            if success {
                print("유저가 생성되었습니다.")
                let vc = CardController()
//                self.dismiss(animated: true)
                vc.modalPresentationStyle = .fullScreen
                self.present(vc, animated: true)
            } else {
                print("다시 수정해주세요")
                self.showAlert(type: .signInFailure)
            }
        }

위 코드에서는 UIAlertController로 각 문제별 이슈를 안내할 수 있도록 처리해보았는데,
발생할 수 있는 한 가지 에러에 대해 맞춤 형식으로 알림이 뜰 수 있도록 짜 두었다.
🤔 여기에도 고민거리가 생겼는데, 단계별로 마주할 수 있는 모든 에러를 처리하는 과정을 생각했었는데 생각보다 오류 알림이 계속해서 나타나게 된다면 사용자가 피곤해질 것 같다는 생각이 들었다.

예를 들어 비밀번호의 구조를 바라보자.
1. 첫문자는 대문자
2. 마지막 문자는 숫자
3. 비밀번호 길이는 8자 이상

위 비밀번호 조건만 따지더라도 값이 입력되지 않은 상황을 추가하면 4가지의 분기가 존재한다.
사용자가 첫 조건만 부합하는 비밀번호를 작성하고 회원가입을 한다고 보자.
이 경우, 2번 조건에 해당하는 에러 알림이 뜰 것이다.

사용자가 알림에 맞춰 수정을 하더라도 - 8 글자보다 짧을 경우 세번째 조건에서 다시 한번 수정 알림이 등장할 것이다.
이 상황에서 사용자는 우리 어플에 가입을 하고 싶은 마음이 들까??


특정 상황에 따라서는 분기별 에러처리가 아닌 하나로 묶어 처리를 하는 방식
또는 다른 접근으로 최초 가입 단계에서 조건에 부합하는 데이터를 작성하도록 만들어야겠다는 생각이 든다.


이메일은 아래와 같이 validation check 함수가 이미 존재한다고 한다!!!
오!!!
https://firebase.blog/posts/2017/02/email-verification-in-firebase-auth/

0개의 댓글