ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Singleton에 대한 의문과 의심
    기타 2022. 8. 26. 12:43

    기존 프로젝트를 리팩토링 하는 과정에서 문득 들었던 의문이다.

    통신을 통해 가져온 유저 데이터를 앱 실행중에 어떤식으로 가지고 있을까에 대한 고민중에 singleton과 userkey를 생각했다.

     

    singleton 과 userDefault

    자, 그럼 둘중에 어떤 기술을 사용할지 선택해야 한다.

    잠깐… userDefault도 내부적으로 singleton 패턴을 사용해서 저장하지 않나?

    일단 비교해보자..

    • 사용 난이도
    • 똑같다. singleton과 userDefault 모두 바로 접근하여 값을 가져올 수 있다.
    • 안정성userDefault는 key-value 타입이다. 사용자가 직접 key를 입력해서 값을 가져온다.뭐… userDefault가 side effect로 부터 singleton에 비해 조금 더 강하다고 할 수 있겠다.
    • 또한 객체에 할당해서 의존성을 주입 할 수도 있다.
    • 안정성은 데이터의 무결성이다. side effect로 부터 안전하고 데이터가 보장된다는 것이다.
    • 데이터의 생명주기
      • userDefault - 앱이 종료 되어도 살아있다.
      • singleton 패턴 - 앱이 종료되면 사라진다.

    singleton에 대한 의문

    singleton 패턴 사용에는 언제나 많은 의문이 따른다.

    심지어 singleton 패턴을 지양해야 한다고들 한다.

    그럼 언제나 왜? 왜 그래야해? 심지어 애플에서도 쓰는데? 라는 의문이 들었다.

     

    그럼 singleton의 장점 보다는 단점과 부작용에 대해 생각해보자.

    뭐 메모리의 낭비 방지, 객체 지향에 위배, testable 하지 못한 코드 등등의 이유 말고 사용자들에게 직접적으로 영향을 미치는 이유

    그게 과연 무엇일까?

    싱글톤의 장점이 무엇인가? 어디에서든 데이터에 접근하여 읽을수 있고, 쓸수도 있다는게 장점이다.

    하지만 이 장점은 곧 단점이 될 수 도있다.

     

    멀티 쓰레드 환경을 생각해보자.

    하나의 쓰레드에서 싱글톤 데이터를 가지고 로직을 돌리고 있다. 이때 다른 쓰레드에서 싱글톤 객체의 데이터가 수정된다면, 앞서 작업하던 쓰레드에서의 데이터 보장이 되지 않는다.

    때문에 싱글톤 패턴에 대해서 설계적으로 완벽하지 않다면 조심해서 사용해야 한다고 생각된다.

     

    다시 프로젝트로 돌아가보자.

    로그인 시 네트워크 통신을 마치고 completion으로 넘어오는 userKey를 singleton 객체에 써준다.

    이 싱글톤 객체는 사용자가 프로그램을 돌아다니며 사용하는 동안 변경 될 일이 없다.

    즉, 로그인과 로그아웃 시점 빼고는 데이터를 write할 일이 없다는 이야기다.

    또한 앱이 종료 되었다가 실행될 때마다 userDefault의 userKey에 대한 정보를 초기화시켜줄 필요도 없다.

    struct UserData: Codable {
        static var shared = UserData(nickname: "", pw: "", userKey: "")
        
        private init(nickname: String, pw: String, userKey: String) {
            self.userpw = pw
            self.nickname = nickname
            self.userKey = userKey
        }
        var userpw: String
        var nickname: String
        var userKey: String
        
        enum CodingKeys : String, CodingKey {
            case userpw = "user_pw"
            case nickname
            case userKey
        }
    }
    

    유저의 데이터를 저장할 UserData 구조체이다.

    private 생성자로 한번의 내부에서의 초기화 이후에 다시 초기화가 되지 않도록 했다.

    func login() {
    		...
            api.requestData(
                endPoint: endpoint,
                dataType: UserData.self
            ) { result in
                switch result {
                case .success(let userData):
                
                    UserData.shared = userData
                    
                case .failure(let error):
                    ...
                }
            }
        }

    login 통신이 끝난 후 response 값을 UserData라는 싱글톤 객체에 넣어줬다.

     

     

    결론

    싱글톤을 사용하는 것에 대한 확실한 근거와 설계가 있다면 두려워하지 말고 사용해도 된다고 생각한다.

    댓글

Designed by Tistory.