본문 바로가기

프로그래밍/Android

[Android] 클린 아키텍쳐 (Clean Architecture)

https://www.apogeonline.com/persone/robert-martin/

클린 아키텍처란 무엇일까?

안드로이드를 어느 정도 개발하다보면 클린 아키텍처라는 것을 들어본 적이 있을 것이다.

 

「 클린 코드(Clean Code)」 를 저술한 Robert C. Martin 선생님이 제안한 시스템 아키텍처로 시스템을 독립적인 계층으로 분할하고, 의존성의 방향을 역전시키는 것을 중점으로 두는 아키텍처 스타일이다.


클린 아키텍처를 사용하게 되면 비즈니스 논리를 확장하고 변경하기 쉽게 만들며, 테스트 가능성과 유지보수성을 향상시킬 수 있다.

 

 

클린 아키텍처의 구조

 

클린 아키텍처가 무엇인지 검색하면 다음과 같은 구조를 많이 볼 수 있다.

 

그림과 같이 클린 아키텍처는 4가지로 구성이 되어있고, 각 화살표의 방향은 의존성을 의미한다.

 

클린 아키텍처의 의존성은 밖에서 안으로 향하기 때문에 바깥 원에 속하는 요소들은 안쪽 원의 요소에 영향을 끼치지 않는다.

 

1. Enterprise Business Rules (핵심 업무 규칙)

 

엔티티는 설계하려는 시스템의 핵심적인 부분으로 핵심 업무 규칙(비즈니스 로직)을 지정하여 캡슐화하고, 이를 통해 데이터의 일관성무결성을 유지하는 역할을 한다.

 

예를 들어서 은행 어플리케이션이 있다고 하면, 은행 어플리케이션은 각각의 고객 엔티티, 계좌 엔티티, 거래 엔티티를 가지고 있다.

 

각 엔티티에는 고객 정보, 계좌 잔액, 거래 세부 내역 등의 어플리케이션의 핵심적인 데이터가 들어가 있고, 이 핵심 데이터는 업무 규칙을 적용하여 관리하게 된다.

 

 

2. Application Business Rules (어플리케이션 업무 규칙)

 

유스 케이스는 어플리케이션이 제공해야 하는 기능과 작업 명세서를 나타낸다.

 

위와 동일하게 은행 어플리케이션을 예시로 들면, 사용자가 제공한 계좌 번호를 사용하여 잔액을 계산하는 등의 비즈니스 로직을 수행하는 것이다.

 

 

3. Interface Adapters

 

인터페이스 어댑터는 외부 시스템 또는 프레임 워크와 시스템 내부 레이어 간의 통신을 담당한다.

 

외부 시스템 인터페이스를 내부 시스템에서 사용할 수 있는 형태로 변환한다. 

 

DB나 웹 서비스에서 받아온 데이터를 유스 케이스나 엔티티가 사용할 수 있는 형태로 변환한다는 것이다.

반대로, 내부 시스템의 데이터나 로직을 외부 시스템이 사용할 수 있는 형태로 변환 시키기도 한다.


컨트롤러, 프레젠터와 같은 컴포넌트를 통해 데이터를 UI에 표시하는 작업 등이 그 예시이다.

 

 

4. FrameWorks & Drivers

 

Framework는 시스템의 특정 기능을 구현할 때 사용되는 소프트웨어 환경이나 플랫폼을 말한다.


예를 들어서 안드로이드 어플리케이션의 경우 안드로이드 프레임 워크가 UI 구성 요소를 제공하고,  SQLite와 같은 데이터 액세스 프레임 워크도 제공을 하게 된다.


Driver는 외부 환경 간의 통신 담당 구성 요소이다. 사용자 터치 이벤트를 예시로 들 수 있다.

 

 

왜 Clean Architecture를 사용해야 할까?

 

어떤 웹 서비스가 꽤나 성공을 하게 되어서 어플리케이션으로 서비스를 확장하게 되었다고 가정해보자.

 

그런 요청을 받게되면 우리는 어플리케이션을 처음부터 새로 만들어야 할까?

 

클린 아키텍처를 적용하였다면 그 대답은 No가 된다.

 

서비스 그 자체 즉, 비즈니스 로직은 변하지 않기 때문에 Frameworks & Driver, Interface Adapters 만 바꿔주면 된다!

 

이처럼 클린 아키텍처는 서비스가 확장함에 따라서 유연하게 대처할 수 있도록한다.

 

많이 헷갈리는게 클린 아키텍처를 검색하면 안드로이드 앱 아키텍처에 관한 정보가 많이 나온다.

 

그렇다면 안드로이드 앱 아키텍처는 클린 아키텍처일까?

 

안드로이드 앱 아키텍처는 클린 아키텍처의 원칙 일부를 차용하여 안드로이드 플랫폼에 맞춤화된 형태로 제공된 형태이다.

 

 


 

Android App Architecture (앱 아키텍처)

https://developer.android.com/topic/architecture?hl=ko

 

안드로이드 공식문서에서는 앱이 성장함에 따라 확장성과 테스트의 용이성, 유지보수 등을 향상시키기 위해 필요 기능 간의 관심사를 분리해야 한다고 말한다.

 

즉, 책임 소재를 좀 더 명확히 하여 불필요한 책임을 지지 않도록 하는 것이 아키텍처 설계의 시작이라고 볼 수 있다.

 

위에서 보았던 클린 아키텍처 구조를 안드로이드 버전으로 나눠본 그림이다.

 

 

위 그림을 좀 더 심플하게 나타내면 다음과 같이 나타낼 수 있다.

 

레이어는 UI, Domain, Data Layer 총 3가지로 나눌 수 있고, Domain Layer의 경우 필수적인 Layer는 아니다.

 

각 화살표는 레이어 모듈 간의 의존 관계를 의미한다. (단방향 참조)

 

하나 중요한 개념은 데이터의 흐름은 2가지의 단방향 흐름으로 나눌 수 있다는 것이다.

 

1. UpStream 방식

사용자가 클릭, 입력 등 이벤트를 발생 시키면 이를 UI Layer -> Domain Layer -> Data Layer 로 상위 전달하는 방식의 데이터 흐름

 

2. DownStream 방식

반대로 외부에서 받아온 데이터를 Data Layer -> Domain Layer -> UI Layer로 하위 전달하는 방식의 데이터 흐름

 

 

UI Layer

UI Elements Module

UI 구성 모듈은 UI 요소 그 자체를 의미한다. Activity/Fragment + xml view 또는 Compose UI가 여기에 해당한다.

 

UI State Holder Module

UI 상태 홀더 모듈은 ViewModel을 통해 구현된다.

 

상태 관리 홀더 클래스인 LiveData나 StateFlow를 통해 UI에 바인딩 하는 데이터를 보유한다.

 

UpStream 관점에서의 ViewModel은 사용자의 이벤트를 받아 비즈니스 로직을 시작시키는 책임을 지고 있다.

 

DownStream 관점에서는 Data Layer에서 데이터를 받아 UI에 데이터를 바인딩하는 책임을 지고 있다.

 

 

Domain Layer

도메인 레이어는 Use Case 모듈로 구성한다.

 

Use Case의 역할은 2가지로 볼 수 있다.

 

1. ViewModel이 짊어지는 책임 외의 비즈니스 로직을 책임진다.

 

2. 여러 ViewModel에서 사용되는 중복 코드를 정의하여 사용한다.

 

두가지 케이스에 대한 설명은 다음 게시글에서 다뤄보도록 하고, 현재 포스팅에서는 Use Case의 역할 정도만 이해하고 넘어가자!

 

 

Data Layer

Repositories

리포지토리도 Up/Down Stream 관점에서 보면 필요한 데이터를 Data Source에게 요청하고(Up), Data Source에서 받아온 데이터를 새로운 모듈로 가공하여 하위 레이어(Domain, UI)에 전달하는 역할을 한다.

 

또한, 가공한 데이터를 Repository 모듈에 캐싱하기도 한다.

 

 

음식점이 마트에 식자재를 주문하는 것, 주문한 식자재를 받아 소비자가 주문한 요리를 만들어서 제공하는 것과 같은 역할을 수행한다고 생각하면 된다.

 

Data Source

데이터 소스도 UpStream 관점으로 보면 Remote나 Local Server에 데이터를 요청하는 역할을 수행하고, DownStream 관점으로 보면 Repository에 받아온 데이터(raw)를 제공하는 역할을 수행한다.

 

 

마치 마트가 농부들에게 야채, 과일 등을 주문해서 받아와 이를 음식점과 같은 소비자에게 다시 제공하는 것과 같다.

 

 

Summary