Beeeam

Clean Architecture 본문

개발

Clean Architecture

Beamjun 2023. 5. 5. 02:35

Clean Architecture

계층을 분리하여 코드 간의 관심사를 분리하는 프로그램 구조이다.

위와 같이 4개의 계층으로 분리된다.

  • Frameworks & Drivers: DB, 프레임워크, 웹, UI, HTTP 등으로 구성되는 계층이다. 가장 바깥에 위치하는 계층이다.
  • Interface Adapter: 어댑터들로 구성된다. 데이터를 UseCase, Entity에서 사용하기 편한 형식으로 변환한다. 순수한 비즈니스 로직만 담당하는 역할을 한다.
  • UseCase: 어플리케이션에 특화된 업무 규칙, Entity로 들어가고, 나가는 데이터의 흐름을 조정한다.
  • Entity: 핵심 업무 규칙 모든 플랫폼 어플리케이션에서 재사용 가능해야 한다.

클린 아키텍처에서 의존성의 흐름은 중요하다. 바깥 원에서 안쪽 원으로 의존하고 있고 안쪽 원은 바깥 원의 정보, 존재를 알아서는 안된다.

그리고 안쪽 원은 바깥 원의 요소를 참조하거나 영향을 줘서는 안된다.

안에서 바깥으로 갈 수록 덜 중요하고 덜 세부적인 표현이 들어간다. ⇒ 안쪽 원으로 갈 수록 더 추상적인 개념으로 표현이 된다.

잘 변경되는 요소는 바깥 원에, 잘 변경되지 않는 요소는 안쪽 원에 위치하게 된다.

 

Clean Architecture in Android

다음과 같이 안드로이드에 클린 아키텍처를 적용할 수 있다.

위의 사진과 같이 presentation, domain, data로 3개의 모듈로 나누어서 관리할 수 있다. presentation과 data는 domain을 의존하고 있고, domain은 어떠한 계층도 의존하지 않는다.

안드로이드 프로젝트에서 Entity는 다른 플랫폼과 사실상 공유하기 힘들어서 domain 모듈에 Entity와 UseCase를 통합하였다.

이와 같이 구성이 될 수 있다.

Domain 모듈

앱의 중심부로 이 계층에 있는 비즈니스 로직은 앱에서 가장 중요한 부분이다. 가장 중요하기 때문에 변경되면 안되므로 domain 모듈은 어떠한 모듈에도 의존하지 않는다.

포함 요소 Entities(DTO, Pojo, VO), UseCase, Repository interface

Data 모듈

데이터 소스(DB, 서버)와 상호작용 하는 코드들이 포함되는 계층이다. data 모듈은 domain 모듈에 의존한다.

Data 모듈의 책임

  • 데이터 입출력 코드는 하나의 계층에서 관리
  • 데이터 소스들과 데이터 소비하는 다른 계층과의 경계를 둔다.

data 모듈에서는 domain 모듈에서 선언한 repository interface를 구현하는데 이 패턴이 구글에서 추천하는 repository 패턴이다.

데이터 소스와 데이터를 소비하는 계층을 다르게 모듈로 구분하였기 때문에 데이터 소스에 변경이 생겨도 비즈니스 로직에는 어떠한 영향도 없어서 안전하다.

Presentation 모듈

Presentation 계층에서는 UI와 관련된 코드를 캡슐화 한다. 그리고 domain 계층에 의존한다.

UI는 비즈니스 로직에 비해 변경되는 일이 많다. 그리고 UI와 관련된 유닛 테스트는 어렵기 때문에 최대한 다른 계층과 의존성 없이 독립적으로 만들어야 한다.

제어의 흐름

안드로이드에서는 보통 사용자의 입력 또는 시스템 이벤트를 받아서 UseCase를 통과하여 해당 입력에 대한 처리를 하고 이 결과를 View에 렌더링하는 흐름을 사용한다.

domain 계층에서 데이터를 처리하려면 data 계층을 호출해야 한다. 근데 domain 계층은 어떠한 계층에도 의존하면 안된다. 그럼 어떻게 처리를 해야 할까? 이러한 경우에 의존성 역전 법칙을 사용한다.

 

의존성 역전 법칙

클린 아키텍처에서 의존성 법칙에 의하면 의존성은 바깥 원에서 안쪽 원으로 흘러야한다.

이러한 의존성 법칙을 어기지 않기 위해서 의존성 역전 법칙을 사용한다.

이는 인터페이스를 이용하여 구현한다. 두 계층 사이에 인터페이스를 추가하여 의존성을 역전 시키면 된다.

위와 같이 UseCase와 Controller 사이에, Controller와 Web 사이에 인터페이스를 구현하여 이를 통해서 의존성을 역전 시킨다.

예시

domain 계층에 UseCase와 Repository interface를 선언 되어있다. 그리고 data 계층에 ApiClient와 Repository interface의 구현체인 RepositoryImp가 선언 되어있다.

제어의 흐름에 따라 UseCase에서 데이터를 받아야 한다. 그러려면 UseCase에서 ApiClient를 호출해야 하는데 UseCase는 domain 계층이므로 어떠한 계층에도 의존하면 안된다.

이럴 때 interface를 사용하여 의존성 법칙을 사용한다.

UseCase는 같은 domain 계층에 있는 Repository interface를 호출하여 데이터를 받아오는 동작을 하게 한다. 그리고 Repository interface의 구현체인 RepositoryImp에서 ApiClient를 호출하여 데이터를 받아오는 동작을 선언한다. 그러면UseCase는 같은 domain 계층에 있는 Repository interface에 의존하고, data 계층에 있는 RepositoryImp은 domain 계층에 있는 Repository interface에 의존한다. 그러면 안쪽 원에서 바깥 원으로 의존하지 않기 때문에 의존성 법칙을 위반하지 않고 의존성을 역전 시킬수 있다.

'개발' 카테고리의 다른 글

OAuth(Open Authorization)  (0) 2023.05.28
Json Web Token (JWT)  (0) 2023.05.22