[Flutter]Repository 리펙터링 { firebase google auth }

임물렁·2025년 3월 27일

google Auth 리펙터링

목록 보기
2/2

기존의 구성은 이러한데,
문제가있다.
Repository는 상태를 가지면 안된다. 항상 필요한 데이터를 그때그때 가져오도록 바꿔야 한다.

기존의 Repository 코드

abstract interface class LoginRepository {
  Future<UserModel?> signInWithGoogle();
  Future<void> signOut();

  UserModel? get user;
}

class LoginRepositoryImpl implements LoginRepository {
  final LoginService _loginService = LoginService();
  UserModel? _user;
  UserModel? get user => _user;
  @override
  Future<UserModel?> signInWithGoogle() async {
    final UserCredential? userCredential = await _loginService.signInWithGoogle();
    _user = UserModel.fromFirebase(userCredential!.user!);
    return _user;
  }

  @override
  Future<void> signOut() async {
    // TODO: implement signOut
    await _loginService.signOut();
  }

}

문제점

UserModel? _user;
UserModel? get user => _user;

Repository가 상태를 가지면 안됌,
Repository의 책임데이터를 전달 하는 것이지, 상태를 보존하거나 관리하는게 아님

하지만 user를 저장하지 않고
viewModel 에서 직접 FirebaseAuth로 접근하면
FirebaseAuth와의 의존성이 강해진다
( 나중에 Firebase를 안쓰게 될 경우 빼기가 힘들어짐 )

개선할 점

-Service : 현재 유저를 가져오는 메서드 추가

  User? getCurrentUser() {
    return FirebaseAuth.instance.currentUser;
  }

-repository

class LoginRepositoryImpl implements LoginRepository {
  final LoginService _loginService = LoginService();

  @override
  Future<UserModel?> signInWithGoogle() async {
    final UserCredential? userCredential =
        await _loginService.signInWithGoogle();
    if (userCredential == null) return null; //null 체크
    //상태를 저장하지 않고 바로 리턴, "데이터를 전달"
    return UserModel.fromFirebase(userCredential.user!); 
  }

  @override
  Future<void> signOut() async {
    // TODO: implement signOut
    await _loginService.signOut();
  }

  @override
  UserModel? get currentUser {
    final user = _loginService.getCurrentUser();
    return user != null ? UserModel.fromFirebase(user) : null;
  }
}

상태를 저장하지 않고 바로 리턴,

-homeViewModel -> user를 띄울때 현재 유저를 받아옴
그때그때 가져오는 식으로 변경

class HomeViewModel with ChangeNotifier {
  final LoginRepository _loginRepository;

  HomeViewModel(this._loginRepository);

  bool _isLoggedIn = true;
  bool get isLoggedIn => _isLoggedIn;

  //FirebaseAuth에 직접 접근하지 않아도 됨.
  UserModel? get user => _loginRepository.currentUser;

  Future<void> signOut() async {
    await _loginRepository.signOut();
    _isLoggedIn = false;
    notifyListeners();
  }
}

결론

1.Repository는 상태(_user)를 가지면 안 된다
• 이유: Repository는 데이터 액세스 계층이기 때문에 상태를 보존하는 책임이 없다.
• 👉 UserModel? _user 제거, 대신 그때그때 현재 유저를 FirebaseAuth로부터 직접 가져와야 함
2. Service는 매번 생성돼도 괜찮은 구조여야 함
• 이유: Stateless 구조가 바람직하고, 의존성 관리가 쉬움
• 👉 LoginService는 상태 없이 호출만 담당하도록 구성
3. 로그인 상태는 ViewModel에서 판단해야 한다
• ViewModel은 상태를 관리하는 책임이 있으므로,
• 👉 currentUser != null 을 ViewModel에서 판단하고 UI에 반영
4. Context로부터 repository를 주입할 필요도 없어짐
• Repository는 의존성만 주입받고, 상태는 직접 갖지 않기 때문에
• ViewModel에서만 의존성 주입하면 깔끔함

🔥추가적으로 get user는 언제 호출되는가?

뷰에서 viewModel.user를 호출할때마다
UserModel? get user => _loginRepository.currentUser;
해당코드 실행,
즉 가지고 있지않고, 그때그때 가져오는 형태임

profile
마감을 떠올리며 과정을 하나씩 되짚는

0개의 댓글