처음 학습하면서 작성한 글입니다. 필요시 추후 내용을 수정할 예정입니다.
틀린 부분이 있으면 언제든 지적해주면 감사하겠습니다 :)
해당 게시글에 사용되는 예제 코드는 gitHub 에 업로드 해두었습니다.
https://github.com/HeeGyeong/CleanArchitectureSample
저번 개념 정리 게시글에 이어서, 실제 예제를 보면서 어떤식으로 Clean Architecture 가 구현되는지 확인해보자.
클린 아키텍처의 개념에 대해 잘 모르는 경우 이전 글을 참고하길 바란다.
https://heeg-develop.tistory.com/2
자, 그럼 예제를 만들어보는 것에 앞어서
모듈의 생성부터가 시작이다.
이러한 방식으로 presentation, domain, data layer 에 대한 모듈을 생성하자.
물론, 기존에 생성되어있던 app 모듈을 제거해도 상관 없고 위의 3가지 모듈 중 하나로 생각하고 (혹은 Refactor 를 통해 Rename) 사용해도 무관하다.
그렇게 생성하고 나면 다음과 같은 형태로 프로젝트 구조가 잡힐 것이다.
그 후에는 이제 각 계층에 맞춰서 필요한 package 를 생성하고, 클래스를 만들어서 넣으면 된다.
실제 프로젝트를 진행하게 된다면 패키지를 전부 구분하여 만들어 두고, 의존성을 주입하는 등의 작업을 시작하기는 쉽지 않겠지만, 우리는 공부를 위한 예제를 만드는 것이니 정석(?)대로 만들어 넣어보자.
각 계층에 필요한 것들은 무엇인가 확인해보자.
- Domain Layer : Data Model (Entity), Repository, Usecase
- Data Layer : Local/Remote Data (DTO), DB (Room, Dao), DataSource (Repo), Mapper
- Presentation Layer : UI, VM, DI, Module.
무엇이 필요한지 확인했으면
우선 패키지를 만들어 넣어보자.
* 여기서 필자가 작성해둔 Entity, DTO 에 관련된 부분은 사람마다, 회사마다 어떠한 기준으로 생각하느냐에 따라 다르다고 생각한다. 어쨌든 데이터 클래스 라는 것만 기억하자.
패키지를 만들었으면,
각 패키지에 필요한 클래스들을 생성해주자.
이때 필자는 Presentation 모듈에 관련된 것들부터 생성해주었다. 추상적인 것들을 구현하는 것 보다 실제로 눈으로 확인 할 수 있는.
즉, UI 가 있는 부분부터 구현해 나가는 것이 조금 더 수월하게 진행이 된다고 생각하고, 그렇게 느끼기 때문이다.
라는 건 필자의 생각이고, 사실 자신이 편한 순서대로 구현해 나가면된다. 정답은 없으니까 말이다.
BaseActivity, ViewModel 을 생성하고, DI 관련된 것들을 생성해 준다. 필자는 DI로 Koin 을 사용하였으며 Api, Repository, Usecase, VM 등 필요한 모듈을 생성하여 의존성 주입을 해주었다.
(DI에 관련한 것은 추후 작성 후 링크를 추가할 예정입니다.)
* 2022.03.03 Koin 관련된 게시글을 추가하였습니다.
https://heegs.tistory.com/80?category=916858
util 패키지에는 presentation 에서 사용할 util 클래스를, View 에는 필요한 activity, adapter, ViewModel 을 선언해준다.
가장 하단에 위치하는 데이터바인딩 어댑터에 대한 설명은 다음 글에서 확인하면 사용 방법을 이해할 수 있을 것이다.
https://heegs.tistory.com/59?category=787593
솔직히 말해서 Presentation 모듈에서는 VM을 선언하여 사용하고, 이 VM이 domain 모듈의 Usecase 를 사용하게 된다는 것 뿐이며, 그 외의 코드들은 기존의 다른 구조와 동일하게 사용한다고 생각하면 된다.
그렇다면, VM의 코드를 확인해 보자.
이처럼 해당 VM 에서 사용하는 usecase 를 주입 하여 필요한 데이터를 가져와서 UI에 뿌려주게 되는 것이다.
각 usecase를 주입받아서 이처럼 Usecase 에 선언된 함수를 호출하여 원하는 데이터를 가져오게 된다.
useCase 를 통하여 Repository 구현부를 호출하고 구현부에서 CRUD 를 통해 데이터를 가져오는 형식이다.
(필자는 이 부분의 로직이 가장 이해가 안되고 헷갈렸다)
*
의존성 주입을 위해 Domain, Data 모듈의 참조가 필요하게 되며,
UseCase 사용을 위해 Domain 모듈의 참조가 필요하게 된다.
따라서, Presentation 모듈에서 Domain, Data 모듈에 대한 참조가 생기게 되는 것이다.
이러한 형태로 gradle 에 의존성을 추가해주자.
다음은, 위에 말했던 ViewModel 에 사용할 Usecase 가 들어가는
Domain 모듈을 확인해보자.
domain 모듈에서는 실제로 UI 작업에 사용할 모델 (Entity) 가 필요하며, 해당 모델을 통해 원하는 데이터를 가져오기 위한 Repository Interface 와 Usecase 를 선언한다.
Usecase 가 무엇인지에 대한 것은 다음 글에서 확인하면 좋을 것이다.
https://heegs.tistory.com/58?category=915533
Usecase를 사용함으로써 해당 VM 이 어떠것을 하고자 하는지 직관적으로 파악할 수 있으며, 의존성을 줄일 수 있다는 장점을 가지고 있기 때문에 Usecase 를 사용한다.
Usecase 는 직관적으로 어떠한 서비스를 제공하는지 알 수 있도록 네이밍을 해주어야 한다.
그리고 다음과 같이 repository 를 사용하여 각 Usecase 별로 원하는 데이터를 가져올 수 있도록 함수를 구현해 준다.
*
domain 모듈에서는 다른 모듈의 별다른 참조가 필요하지 않게 된다.
그렇기 때문에, presentation 모듈에서 처럼 gradle 에 다른 모듈에 대한 참조를 추가할 필요는 없다.
마지막으로, data 모듈을 확인해보자.
Data 모듈에서는 로컬(DB) 데이터와 서버(API) 데이터를 모두 가져와서 사용하기 때문에 이에 대한 패키지를 만들어 구분지어 주었다.
API, DB, Model 에 관련된 소스코드는 별 다른거 없이 기존에 사용하던 방법과 동일하니 설명은 생략한다.
전체 코드는 본 게시글 상단의 깃허브를 확인하길 바란다.
각 DataSource 들은 위의 api, db 를 통해 데이터를 컨트롤 하는 CRUD 라고 생각하면 편하다.
하지만 API 를 사용하는 DataSource 의 경우 api 를 통해 값을 가져오는 것 밖에 하지 못하므로 api 의 의존성이 높아 개발자가 임의로 추가, 제거하기는 쉽지 않다. (서버와의 커뮤니케이션이 필요해진다)
반대로, Local 의 경우 DB (Room) 에 저장하여 사용하는 부분이기 때문에 개발자가 원하는데로 데이터를 컨트롤 할 수 있게 된다.
따라서,
- RemoteDataSource 는 API에 맞춰서 구현을 해야하는 것이고
- LocalDataSource 는 개발자가 필요한 데이터를 가져오도록 커스터마이징이 가능하다.
마지막으로 Domain 모듈에서 선언했던 Repository 의 구현부이다.
이 구현부에서는
- 위에 선언한 DataSource 들을 인자로 받아서 사용하며,
- Domain 모듈의 Repository에서 선언하였던 함수들을 override 하여
- 원하는 데이터를 Presentation 계층으로 던져주는 부분
을 구현해주면 된다.
이처럼 각 DataSource 를 사용하여 원하는 데이터를 Local 혹은 Remote 에서 가져오고, 원하는 데이터 타입/형태로 만들어서 return 시켜주면 되는 것이다.
여기서, Mapper 클래스를 사용하여 원하는 데이터 타입/형태로 만들어 던지게 된다.
해당 예제에서는 DTO 와 Entity 객체의 형태가 동일하게 사용되기 때문에 그대로 값을 던져주는 형식으로 구현이 되어있지만, 실제 사용시에는 가져온 데이터와 사용할 데이터의 차이가 있기 때문에 해당 함수를 통해 변환시켜서 전달하도록 구현한 것이다.
*
Mapper 클래스나, Repository 의 구현부를 사용하기 위하여 Data 모듈에서는 Domain 모듈의 참조가 필요하게 된다.
이런식으로, Clean Architecture 의 3가지 계층을 모듈로 나누어서 생성하고, 각 모듈에 따른 의존성을 gradle 로 추가한다.
그 후, 각각 모듈의 특성에 맞춰서 필요한 클래스들을 선언하여 사용한다.
라는 아주 간단하고 깔끔한 개념이다.
하지만, 생각보다 구현하는데 생각을 많이 하게 되는 아키텍처라고 생각된다.
예제를 만들기 전까지는 머리로는 이해해도 실제로 어떻게 구현을 해야할지 막막했지만, 예제를 만들어보니 이해도 빠르고 어떻게 구조를 잡아야하는지 감이 잡히는 것 같다.
역시, 이론 공부도 중요하지만 실제로 해보는게 지식 습득에는 큰 도움을 준다.
해당 게시글에 사용되는 예제 코드는 gitHub 에 업로드 해두었다.
https://github.com/HeeGyeong/CleanArchitectureSample
*
해당 예제를 만드는데 참고한 블로그입니다.
https://youngest-programming.tistory.com/484#comment14822944
'Android > Architecture' 카테고리의 다른 글
[Android] Coordinator Pattern (0) | 2022.02.15 |
---|---|
[Android] Clean Architecture 실전 압축 정리 - Data Flow (0) | 2022.02.10 |
[Android] Clean Architecture - UseCase 란 ? (0) | 2022.02.06 |
[Android] Clean Architecture 실전 압축 정리 - 개념 (0) | 2022.02.04 |
[Android] 싱글톤(Singleton) 패턴 (0) | 2020.06.11 |