MVVM with Repository

ideal dev·2023년 2월 11일
2
post-thumbnail

오늘은 안드로이드 스튜디오에서 레파지토리 기능을 구현 중 context 가 필요하여 관련 내용을 공부했습니다.
공부한 내용은 아래 목차와 같이 포스팅할 예정입니다.

  1. MVVM with Repository
  2. context
  3. Repository 에서 context 사용하기

이번 포스팅에서는 1. MVVM with Repository 에 관해 알아보도록 합니다.

MVVM 이 뭐야 ?


처음 이 디자인 패턴을 접했을 때는 개념이 너무 안와닿았아서 최대한 쉽게 설명해보려 합니다.
먼저 MVVM 이 무엇의 약자인 지, 왜 필요한지에 대해 생각해보아야겠죠.

MVVMModel - View - ViewModel 의 약자이구요!

그림순으로 나열한다면 View - ViewModel - Model 이 되겠네요.

간단하게 설명해보자면 한 곳에서 구현되던 기능을 View, ViewModel, Model 로 각각 기능을 나누어 구현하겠다. 라는 것 입니다.

그럼 왜 MVVM이 필요한거고 , 왜 기능을 나눠야 하죠 ?

저희가 더 나은 프로그램을 만들기 위해 노력하는 게 어떤게 있을까요?
다음 사람이 내 코드를 보기 쉽게 만들고, 재사용 및 유지보수가 용이하고, 확장성있게 만들려는 노력을 합니다.
이를 위해서는 코드를 보다 깨끗하고 정확하며 읽기 쉽고, 유지 관리 가능하게 해야겠죠 !
그러기 위해 코드 각각을 분리 (의존성 분리 ) 하는 것 입니다.


예를 들어 하드디스크에 파일을 보관하고 가족들이 필요할 때 마다 확인한다고 생각해봅시다.

파일 저장 형태 - 하드디스크 내부
우리집 강아지.jpg, 내 사진.jpg, 생일파티영상.mp4, 내가 좋아하는 노래.mp3, 언니 사진.jpg, 내 이력서.hwp, 엄마 사진.jpg, 가족여행사진.jpg, 언니 이력서.hwp, 아빠 사진.jpg

이러한 여러 파일을 위와 같이 저장해두면 어떻게 될까요?
모든 가족들이 파일 이름 하나하나를 비교하며 자신이 현재 필요한 문서를 찾기 위해 전체를 확인해볼 것 입니다.

운이 좋으면 바로 찾고 운이 안좋으면 파일 목록 하나하나를 확인해보며 나올 때 까지 찾아야겠지요,
하지만 우리는 어떻게 하면 더 효율적일 지 이미 알고 있습니다.

폴더로 구분하는거죠!

파일 저장 형태
'나' 폴더 - 내 사진.jpg, 내가 좋아하는 노래.mp3, 내 이력서.hwp
'언니' 폴더 - 언니 사진.jpg, 언니 이력서.hwp
'엄마' 폴더 - 엄마 사진.jpg
'아빠' 폴더 - 아빠 사진.jpg
'강아지' 폴더 - 우리집 강아지.jpg
'가족' 폴더 - 생일파티영상.mp4, 가족여행사진.jpg

그럼 누가 사용하든 자신의 폴더에 들어가 원하는 파일을 찾을 수 있습니다.
여기서 더 효율적이게 만들려면 폴더 내의 파일명으로도 분리가 가능하겠죠!

파일 저장 형태
'나' 폴더
- '사진' : 내 사진.jpg
- '음악' : 내가 좋아하는 노래.mp3
- '한글' : 내 이력서.hwp

이런 식으로 말이죠!
우리는 그럼 이를 코드에 적용해서 한 곳에 모여있던 코드들을 위와 같이 분리하여 보기 쉽게 만들어 줄 수 있습니다.


일반적인 상황을 가정해보겠습니다.

  1. 유저가 아이디와 비밀번호를 입력
  2. 유저가 화면 내의 로그인 버튼을 클릭
  3. 서버에서 해당 유저의 아이디와 비밀번호가 일치하는 지 확인
  4. 결과값 전송 ( Success or Fail 로 가정 )
  5. 서버에서 받아온 success 신호로 로그인 성공 시 실행되는 코드 실행

위와 같은 상황일 때 LoginActivity 를 생성했다고 가정하고 자바로 간단히 작성해보자면

// string 에서 .equals 를 사용해야하지만 가독성을 위해 == 로 표기했습니다.
// 서버에 id, pw 확인 후 응답값을 returnValue 로 가정

loginbtn.setOnClickListner{ // 1. 로그인 버튼 클릭

	// 2. 서버와 통신
    서버 통신 코드 생략 ..
    
    // 3. 결과값
    returnValue = jsonResponse.getBoolean("success");
	
    // 4. 결과값으로 구분하여 구현
    if(returnlValue){
		Intent intent = new Intent(MainAcitivty.this, LoginActivity.class);
		startActivity(intent);    
    }else { 
         Toast.makeText(getApplicationContext(),"로그인에 실패하였습니다.",Toast.LENGTH_SHORT).show();
        return;
    }
 
    
} ;

살짝 복잡한 느낌이 있지요?
여기서 메소드로 코드를 분리시켜 보겠습니다.

loginbtn.setOnClickListner{ //1. 로그인 버튼 클릭

	// 2. 서버와 통신한 값을 boolean 으로 받아온 후 해당 코드 실행
	if ( userLogin(id, password) ) { 
    	StartMainActivity();
    } else { // 오류 발생 
    }
} ;

// 2-메소드. 통신 후 결과값
public static boolean userLogin(String id, String pw){
	// 서버와 통신
    코드 생략 ...
    
	// 서버에 id, pw 확인 후 응답값을 returnValue 로 가정
    returnValue = jsonResponse.getBoolean("success");
    return returnValue ;
    }
    
 }
 
 public static void startMainActivity(){
	Intent intent = new Intent(MainAcitivty.this, LoginActivity.class);
	startActivity(intent);   
}

자, 각각이 어떤 역할을 하는 지 이해하기 훨씬 간단해졌죠 ?!
예를 들어 자동 로그인 기능을 추가하고자 할 때 메인액티비티 intent 코드를 또 작성할 필요없이 startMainActivity 메소드를 사용하면 됩니다!


어느정도 정리는 되었지만 그래도 LoginAcitivty에 모든 동작 코드가 구현되어 있습니다.
아무리 메소드로 나누어 코드를 처리하려 해도 코드가 계속 쌓인다면 읽기 힘들어 질 것입니다.
물론 동작에 있어 문제는 없지만 체계적인 구조가 전혀 없어 추후에 유지 보수도 어렵겠지요.

그렇기 때문에 디자인 패턴을 적용하여 역할을 분리시키는 것이 필요하고,
저희는 오늘 그 중 하나인 MVVM에 대해 공부하는 것 입니다.

그래서 MVVM 는 독립적으로 구현을 하는데요, 다시 위 상황으로 설명해보겠습니다.

  1. 유저가 아이디와 비밀번호를 입력
  2. 유저가 화면 내의 로그인 버튼(view)을 클릭
    1-1. view : 이벤트 발생, viewmodel 에 데이터 요청
    1-2. viewModel : Model에게 데이터 요청
  3. 서버에서 해당 유저의 아이디와 비밀번호가 일치하는 지 확인
    2-1. Model : View Model에서 요청한 값 반환 ( success or fail )
  4. 서버에서 받아온 success 신호로 로그인 성공 시 실행되는 코드 실행
    3-1. ViewModel : Model로 부터 받은 값을 라이브 데이터에 저장
    3-2. View : LiveData 감지, 저장된 값을 받아옴

이렇게 구현됩니다! 갑자기 너무 어려워졌나요 .. ? 정상입니다 !
더 쉽게 각각의 역할을 한 번 이해해봅시다.

View

Acitivity / Fragment 로 나타낼 수 있습니다.
사용자와 상호작용 (클릭, 입력 등)을 뷰모델에 전달합니다.
ViewModel의 데이터를 관찰하여 UI를 갱신합니다.

ViewModel

View가 요청한 데이터를 Model로 요청합니다.
Model로 부터 요청한 데이터를 받습니다.

Model

ViewModel이 요청한 데이터를 반환합니다.
데이터에 접근하는 ( 내부 DB , 백엔드 API 호출 등) 역할

처음엔 너무 이해가 안갔는데 틀을 딱 잡아준 도표가 있어 저도 적용해보았습니다.
(그려주신 분 너무 감사합니다)

이로써 뷰모델은 자신의 로직에만 집중할 수 있게 되는 것이지요!
관리할 코드와 파일이 많아지지만, 모듈화가 명확해지고 모듈의 교체도 유연해진다는 장점이 있지요!

장점

  • View 가 ViewModel 의 Data 를 관찰하고 있으므로 UI 업데이트가 간편
  • ViewModel이 데이터를 홀드하고 있으므로 Memory Leak 발생 가능성 배제
    (View 가 직접 Model 에 접근하지 않아 Activity / Fragment 라이프 사이클에 의존하지 않기 때문)
  • 기능별 모듈화가 잘 되어 유지 보수에 용이 (e.g. ViewModel 재사용 및 DB 교체 등의 작업이 편리함)

여기까지 오셨다면 MVVM을 거의 삼켜먹었다고 할 수 있습니다.
어렵게 느껴지신다면 바로바로 정상입니다.

기존의 LoginActivity 에서 MVVM 을 적용한다면

View : LoginAcitivity
ViewModel : LoginViewModel
Model : LoginModel

이렇게 두 개의 파일을 더 생성하여 처리를 해야하는거죠!
MVVM 패턴을 적용한 로그인 코드는 다음에 기회가 된다면 다뤄보도록 하겠습니다.
그런데 MVVM을 검색해서 찾다보니 Repository 라는 기능도 알게 되었습니다.


레파지토리가 뭐야 ?

MVVM 디자인 패턴 사용 시, Repository 라는 인터페이스가 존재합니다.


이미지 출처

이전에 설명했던 그림의 ViewModel 과 Model 사이에 Repository 라는 개념이 생겼는데요,
위 그림은 뷰모델이 데이터를 요청하면 "레파지토리"가 가져와서 전달해주네요!

Repository는

  • ViewModel 과 데이터를 주고받기 위해, 데이터 API 를 포함하는 클래스입니다.
  • Repository 의 존재 덕분에 ViewModel 이 데이터를 관리할 필요가 없게 됩니다
  • ViewModel과 Model 사이에 위치하여, ViewModel이 데이터를 요청하면 Repository가 데이터를 가져오거나 저장하는 역할을 합니다.
    • ViewModel은 직접 데이터베이스에 접근하는 것을 막아 로직을 추상화
    • Repository는 데이터 소스 (예를 들어, 데이터베이스, API, 캐시 등)에 대한 접근을 캡슐화하여, ViewModel이 데이터를 처리할 때 추상적인 수준에서 데이터에 접근 가능

~> Repository는 ViewModel과 Model 사이에서 데이터를 중계하는 역할
데이터 액세스 로직을 캡슐화하여 ViewModel의 복잡성을 줄이는 데 도움이 됩니다.

참고

https://medium.com/draftkings-engineering/android-mvvm-and-repositories-in-the-real-world-e54c3582f832
https://velog.io/@dddooo9/Android-MVVM-패턴을-사용하는-이유와-방법
https://velog.io/@haero_kim/Android-깔쌈하게-MVVM-패턴과-AAC-알아보기
이자리를 빌려 저의 MVVM탐험기에 도움을 주어 감사합니다

0개의 댓글