안드로이드 클린 아키텍처
- 로버트 C.마틴 (Uncle Bob) 의 “The Clean Architecture” 라는 이름의 글로 12년 8월 13일에 처음 세상에 모습을 드러냈다.
- 최종 목적은 계층을 분리하여 관심사를 완전히 분리하는 것에 있다.
생각해보자
- 왜 이렇게나 많은 프로그래밍 언어와 프레임워크가 있는거지?
- 누구에게 고수준 프로그래밍 언어가 필요하지?
- 기계는 저수준 어셈블리 보다 고수준 언어를 선호하나?
- 당신의 프로젝트에서 정말 작은 수정인데 두려움을 가졌던 적이 있는가?
- 당신이 작성한 시간이 좀 지난 코드를 다시 이해하기 위해 얼마나 많은 시간을 소비했는가?
- 새로운 동료에게 당신의 프로젝트의 아키텍쳐를 설명하기 위해 얼마나 많은 시간이 필요한가?
클린 아키텍처가 왜 유용한가?
- 새로운 기능이 추가되거나 내부 로직이 변경되어야 할 때 유연하게 대처할 수 있도록 구조화할 수 있다.
- 프레임워크 독립적, 시스템을 프레임워크의 한정된 제약에 억지로 집어넣는 대신 도구로서 사용할 수 있다.
- UI 독립적, UI 변경 시 UI 외의 부분을 변경할 필요가 전혀 없다.
- 데이터베이스 독립적, 심지어 SQL 에서 NoSQL으로 변경해도 아무런 지장이 없다.
(안드로이드의 경우는 Realm 이든 Room 이든 상관이 없다!)
- 쉬운 테스트, 외부 요인 없이 테스트 가능하고, 심지어 테스트 속도도 빠르다!
- 결론적으로, 비즈니스 변경 사항에 최대한 빠르게 대응하며 시스템 경쟁력을 높일 수 있어야 한다.
- 그렇게 하려면, 모듈을 적절한 경계로 나눔으로서 한 모듈에 대해 변경사항이 생기면 다른 모듈을 건드릴 일이 없이 그 모듈만 건들게끔 설계해야 한다.
- 좋은 아키텍처는 툴과 프레임워크에 대한 결정사항을 최대한 뒤로 미룰 수 있어야 한다.
(DB, 웹서버, DI 등)
- 비즈니스 로직이란?
- 하나의 프로젝트나 프로그램 중 업무와 관련된 처리를 하는 일부분을 뜻하는데 프로젝트를 하면서 데이터베이스에서 어떠한 자료를 가져와서 웹에서 출력을 할 때 데이터베이스 연결, 통신, 자료가공, 페이지 구성등 여러 작업을 하지만 그 중에서 사용자가 원하는 자료의 가공 부분을 의미한다. 즉, 어떻게 데이터가 생성, 저장되고 수정되는지를 정의한 것
의존성 규칙


- 대개 바깥쪽으로 향할수록 고수준의 소프트웨어가 되는 경우가 많다.
- 이 때 바깥쪽 원은 메커니즘이고 안쪽의 원은 정책이다.
- 위의 아키텍처를 가능하게 하는 중요 규칙은 바로 의존 규칙이다.
- 규칙에 의해서 소스 코드는 안쪽을 향해서만 의존할 수 있고, 안쪽의 원은 바깥쪽 원에 대해 전혀 알지 못한다.
- 바깥쪽 원에서 선언된 어떤 요소를 안쪽 원에서는 참조하거나 영향을 줘서는 절대 안된다.
- 정리하면, 각각 클래스는 한 가지 역할만 수행하게 만들고, 서로의 의존 관계를 어떻게 할지 규칙을 정해주어야 한다.
.equals("의존성 규칙")
- 메커니즘? 정책?
- 메커니즘 : 어떤 일을 어떻게 할 것인가를 결정 (How)
- 정책 : 무엇을 할 것인가를 결정 (What)
- 예를 들어 안드로이드에서 검색 기능을 구현한다고 했을 때, 유저가 검색 버튼을 누르면 유저 입장에서는 한 번에 검색 결과가 나오는 것처럼 보이지만, 실제로는 내부 비즈니스 로직에 의해 검색 결과가 추출된다. 만약 위의 클린 아키텍처를 따라가면 바깥쪽 원인
View
에서는 단순하게 결과를 받아서 보여주기만 하면 되지만, 안쪽에서는 검색값을 받아서 어떻게 처리할지 결정해야 한다.
Entity
- 비즈니스 규칙을 캡슐화한다.
- 메소드를 갖는 객체일 수도 있으나 데이터 구조, 함수의 집합일 수도 있다.
- 가장 일반적이면서 고수준의 규칙을 캡슐화한다.
- 바깥쪽에서 어떤 것이 변경되더라도 절대 바뀌지 않는다.
- 애플리케이션이 어떤 동작을 하더라도
Entity
계층에는 영향을 주어선 안된다.
Usecase
- 애플리케이션의 고유 비즈니스 규칙을 포함하며, 시스템의 모든
Usecase
를 캡슐화하고 구현한다.
Entity
의 데이터 흐름을 동작을 제어한다.
- 당연히, 여기서 변경이 일어나더라도
Entity
에게는 영향을 주지 않아야 한다.
- 또한, 데이터베이스 - UI에서 변경이 일어나더라도 영향을 받지 않아야 한다.
- 개발자에게 중요한 것은
Usecase
가 정확하게 동작하는 것이다.
Usecase
의 동작 결과를 확인하는 작업을 진행할 때 UI를 필요로 하는 경우는 없어야 한다.
Interactors
라고도 칭해진다.
Interface Adapter
View
등 외부의 기능 혹은 사용 중인 프레임워크에 용이한 형식으로 데이터를 변환한다.
- 안드로이드의 MVVM 패턴에서는
ViewModel
영역이다.
Model
→ Usecase
→ ViewModel
로 돌아가는 데이터 구조일 가능성이 높다.
- 결론적으로 순수한 비즈니스 로직만을 담당하는 역할을 한다.
Frameworks & Drivers(Web, DB)
- 데이터베이스, 웹 프레임워크 등이 위치해있다.
- 웹이든, 데이터베이스든 상세한 정보는 모두 이 곳에 둔다.
- 안쪽의 원과 통신할 연결 코드 외에는 별다른 코드를 작성하지 않는다.
- UI에는 내가 하고자 하는 것들(
Usecase
) 를 구현하는 것이 아니라, 오로지 세부사항이다.
- UI는 단지 내가 무언가를 사용자들에게 보여줄 때나 필요한 것이다.
📱 Clean Architecture in Android
- 2012년 클린 아키텍처에 관한 글이 처음 공개된 이후, 어떻게 하면 모바일 설계에서 클린 아키텍처의 도움을 받을 수 있을지 많은 논의가 있었다.
- 결과적으로 네 개인 계층을 재구성하여 3개의 계층으로 분리하는 것으로 일반화되었다.
- 각 계층이 자체 데이터 모델을 사용하므로 계층 간 독립성을 확보할 수 있다는 것이 중요하다.
- 이 때 계층 간 데이터 변환을 수행하기 위해
Mapper
가 필요해진다.

Domain Layer
- 비즈니스 로직을 포함하고 있으며, 이에 필요한
Entity
와 Usecase
, Repository
를 포함한다.
Domain
레이어는 Presentation
레이어, Data
레이어와 어떤 의존성도 맺지 않아야 한다.
- 순수 코틀린 혹은 자바 코드로 구성되어 있어 다른 프레임워크에서도 유연하게 사용이 가능하다.
Usecase
- 각 기능 혹은 비즈니스 논리 단위로 구성된다.
- 이름만 보고 어떤 기능을 수행하는지 짐작할 수 있어야 한다.
Presentation
레이어의 UI에서 어떤 이벤트 혹은 동작에 의해 호출되는 방향으로 설계한다.
Data
레이어에서 실제 데이터를 어떻게 가져올지 정의는 하지 않고, 해당 메소드를 호출하는 방식으로 데이터를 저장한다.
Translater
Data
레이어의 Entity
를 Domain
레이어의 Model
로 변환하는 역할을 수행한다.
Repository
Domain
레이어에서는 인터페이스로 정의하고, 실제 구현은 Data
레이어에서 진행된다.
Model
- 애플리케이션의 실질적 데이터가 여기에 구현된다.
- 안드로이드와 의존성을 가지고 있어선 안되고, 다른 프로젝트에서도 동일하게 사용할 수 있는 클래스를 작성해야 한다.
Data Layer
Data
레이어는 Domain
레이어에 의존성을 지니고 있다.
Repository
Usecase
가 필요로 하는 데이터 저장, 수정등의 기능을 제공한다.
- 위의
Domain
레이어에서 설계한 Repository
를 실제로 구현한다.
DataSource
- 실제 데이터의 입출력을 진행한다.
Room
을 사용한다고 가정하면 Dao
를 이 부분에서 접근하고 결과를 출력한다.
Entity
Domain
레이어의 Model
과는 다르게, REST API의 요청/응답을 위한 JSON
, 로컬 DB에 저장하기 위한 테이블에 저장하기 위한 데이터를 정의한다.
Presentation Layer
- 내부적으로 프레임워크 의존성을 처리하기 위해
MVP
혹은 MVVM
패턴을 사용한다.
Acitivity
, Fragment
, Presenter
, ViewModel
을 포함한다.
View
- UI 구현과 사용자 입력만을 담당한다.
- 화면에 그려지는 것이 어떤 의미가 있는지는 전혀 알지 못해야 한다.
- 데이터를 지니고 있더라도 화면과 관련된 데이터만 지니고 있어야 한다.
(e.g. : 화면의 좌표)
Presenter (ViewModel)
View
와 달리 플랫폼(e.g. : 안드로이드)
에 직접적으로 의존하지 않으므로 단위 테스트가 가능하다.
- 또한 화면에 그려지는 것이 어떤 의미를 가지고 있는지 알고 있다.
- 사용자 입력이 왔을 때 어떤 반응을 해야하는지에 대한 판단도 이 곳에서 진행한다.
Domain
레이어의 Usecase
를 주입받아 데이터를 가져온다.
- 당연히,
Data
레이어에 의존성이 없기 때문에 데이터를 가져오는 과정에 접근할 수 없다.
정리하면서 배운 것
- 데이터베이스가 중점이 되는 것이 아니라, 앱에 표현할 모델이 중요한 것이다. 데이터베이스는 오로지 부수적인 것이다.
- 회원 리스트가 있다고 했을 때, 애플리케이션에 (이름 - 나이 - 학교) 를 표현할지, (이름 - 나이)만 표현할지가 중요하지 그 데이터를 담을 데이터베이스는 무엇이건 상관이 없다.
- 모든 아키텍처의 지향점은 결국 개발 중 수정사항이 생겼을 때 변경점을 최소화하는 것이다.