안녕하세요. 슬로우플랫폼에서 CPO를 맡고 있는 Shawn이라고 합니다.
슬로우플랫폼은 시니어를 위한 스마트에이징 스타트업입니다.
클라이언트용 앱을 개발해야 하는 상황에서 앱 구조에 대해 다시 한번 생각을 하게 되었습니다.
처음엔 규칙도 잘 지키고 해서 깔끔하게 보이던 소스가 시간이 지나면서 뭔가 이상하게 변하는 코드를 보며 좋은 아키텍처의 필요성을 느끼게 되었습니다. 개발을 하다 보면 급하게 필요한 코드를 추가하거나 비슷한 기능의 코드를 여러 곳에 추가하는 등 원하지 않게 변경되는 소스를 보게 됩니다.
이에 개발자들이 지향하는 구조와 사용해본 안드로이드 진영의 MVVM 패턴의 결합된 구조에 대해 알아볼려고 합니다.
먼저 클린 아키텍처에 대해 간단히 알아보겠습니다.
클린 아키텍처라고 검색을 하면, 대표적으로 위와 같은 구조의 그림을 많이 볼 수 있습니다.
이는 엉클 밥(Robert C. Martin)이 기존의 수많은 아키텍처에 대한 아이디어들을 하나의 실행 가능한 개념으로 통합하려는 시도를 하면서 그리게 되었습니다.
기존의 클린 아키텍처들의 공통 목표는 관심사의 분리입니다.
소프트웨어를 계층으로 나눔으로써 서로에 대한 관심사의 분리와 의존도를 낮추는 것을 달성하게 됩니다.
이 아키텍처를 작동시키는 주요 규칙은 의존성 규칙입니다.
위의 그림의 왼쪽에 있는 화살표의 방향이 의존성을 나타내는 것으로, 의존성 규칙에 따르면 소스 코드 의존성은 안쪽으로만 가야 합니다. 안쪽 원의 어떤 것도 바깥쪽 원의 어떤 것에 대해 전혀 알 수 없습니다. 특히, 바깥쪽 원에서 선언된 것의 이름은 안쪽 원의 코드에서 언급되어서는 안 됩니다. 이는 함수, 클래스, 변수 또는 기타 명명된 소프트웨어 엔터티를 포함합니다.
동일한 이유로, 바깥쪽 원에서 사용되는 데이터 형식은 특히 이 형식이 바깥쪽 원에서의 프레임워크에 의해 생성되었다면 안쪽 원에서 사용해서는 안 됩니다.
엔터티는 Enterprise 규모의 비즈니스 규칙을 캡슐화하는 도메인 계층입니다.
단일 응용 프로그램에서는, 이러한 엔터티는 응용 프로그램의 비즈니스 객체입니다. 이들은 가장 일반적이고 고수준의 규칙을 캡슐화합니다. 외부 변경 사항이 발생할 때 이러한 객체가 영향을 받으면 안됩니다.
어플리케이션 계층으로도 불리는 이 레이어는 어플리케이션 규모의 비즈니스 규칙이 포함됩니다.
이 레이어의 변경이 엔터티에 영향을 주면 안됩니다.데이터베이스, UI 또는 일반적인 프레임워크와 같은 외부 요소의 변경에도 이 레이어가 영향을 받지 않는 것을 전제로 합니다.
어댑터 계층으로도 불리는 이 레이어는 유즈 케이스 및 엔터티 계층의 데이터를 변환하는 어댑터의 집합입니다.
데이터베이스, 웹 또는 UI와 같은 외부 영역에서 사용하기 편리하도록 변환하는 것입니다. GUI의 MVC와 같은 아키텍처를 포함하는 것으로, 프레젠터, 뷰 및 컨트롤러가 모두 여기에 속합니다.
가장 바깥쪽 레이어는 일반적으로 데이터베이스, 웹 프레임워크 등과 같은 세부 사항을 나타내는 계층으로 인프라 계층으로도 불립니다.
일반적으로 이 레이어에서는 안쪽의 원과 통신하는 글루 코드(Glue code)만 작성합니다.
다음으론 클린 아키텍처라고 검색을 하다 보면 MVVM 패턴과 많이 결합하여 구성을 하는 글들을 볼 수 있습니다.
다음으로 MVVM 패턴에 대해 간단히 알아보겠습니다.
MVVM 패턴은 마틴 파울러의 Presentation 모델 패턴에서 파생된 디자인 패턴입니다.
MVVM 패턴의 목표는 비즈니스 로직과 프레젠테이션 로직을 UI로부터 분리하는 것입니다. 비즈니스 로직과 프레젠테이션 로직을 UI로부터 분리하게 되면, 테스트, 유지 보수, 재사용이 쉬워집니다.
뷰의 역할은 UI에 관련된 것을 다루는것 입니다.
사용자가 스크린을 통해서 보는 것들에 대한 구조, 레이아웃, 형태를 정의하는 것입니다. 뷰는 애니메이션 같은 UI 로직을 포함하되 비즈니스 로직을 포함하지 말아야 합니다.
뷰 모델의 역할은 뷰가 사용할 메서드와 필드를 구현하고, 뷰에게 상태 변화를 알리는 것입니다. (뷰는 뷰 모델의 상태 변화를 옵저빙한다.) 뷰 모델에서 제공하는 메서드와 필드가 UI에서 제공할 기능을 정의합니다. 하지만, 뷰가 이 기능을 어떻게 보여줄 것인지를 결정합니다.
일반적으로 뷰 모델과 모델은 일대다 관계를 형성합니다. 뷰 모델은 뷰가 쉽게 사용할 수 있도록 모델의 데이터를 가공해서 뷰에게 제공합니다. 예를 들어, 뷰에서 서로 다른 두 모델의 데이터를 활용한 데이터가 필요하다면 뷰에서 모델의 값을 조작해서 사용하는 것이 아니라, 뷰 모델에서 두 모델의 데이터를 가공하고 뷰에서는 오직 UI만 다루도록 해야 합니다.
모델은 비즈니스 로직과 유효성 검사와 데이터를 포함하는 앱의 도메인 모델로 생각할 수 있습니다. 쉽게 말해서, 모델은 앱에서 사용할 데이터에 관련된 행위와 데이터를 다룹니다.
아래 그림은 MVVM 패턴에서 사용자의 Action이 처리되는 방향과 이에 응답하는 Data가 처리되는 방향을 나타냅니다.
그럼 이제 클린 아키텍처와 MVVM 패턴의 결합된 구조를 알아보겠습니다. 이 구조 역시 클린 아키텍처를 검색하면 많이 나오는 그림입니다.
Presentation 계층과 Data 계층은 Domain 계층을 의존하고 있으며, 각 계층의 세부 영역 역할은 다음과 같습니다.
앞에서 간단히 알아본 내용을 기반으로 우리가 만들어갈 앱의 구조를 그려보았습니다.
클린 아키텍처에 대해 설명한 좋은 글들에서 설명한 구조와 별반 다르지 않습니다.
Presentation - Domain - Data 로 분리된 형태입니다. 우리는 플러터를 이용하여 개발할 것이라 UI부분엔 위젯이 있고, ViewModel 부분에는 플러터 상태 관리 도구가 있습니다.
클린 아키텍처는 많은 개발자들의 경험이 모여서 만들어진 것입니다. 또한 클린 아키텍처를 설명한 많은 글들에서 공통적으로 얘기하는 내용이 클린 아키텍처에는 정답이 없다라는 것입니다.
개발하는 상황에 맞춰 아키텍처를 설계해야 하고, 클린 아키텍처의 중요 원칙인 의존성 규칙을 잘 지킨다면 좋은 아키텍처라는 것입니다.
시작은 위의 구조로 할 것입니다. 결국 개발을 진행하면서, 요구사항을 만족할 수 있는 우리만의 구조를 만들어 나갈 것입니다.
아키텍처에 대한 여러 글들을 보다가 흥미로운 글을 발견했습니다.
앱을 Presentation - Domain - Data 인 3개의 계층으로 나누고, 그 안에 기능들을 구현할텐데, 이렇게 전체 앱의 계층을 상위 수준에서 나눠서 개발하는 것이 최선인가?라는 질문을 하고 있습니다.
왼쪽의 구조는 상위 수준에서 3개의 계층으로 나눈 것이고, 오른쪽의 구조는 모듈(기능)별로 나눈 후, 그 안에서 3개의 계층으로 나눈 것입니다.
앞의 설명과 비슷하게 설명하는 또 다른 글이 있습니다.
이 글 역시 기능을 먼저 정하고, 각 기능 안에 Presentation - Domain - Data 으로 3개의 계층을 나눴습니다.
앱 내의 분리 기준으로 기능이 기준이 되어야 한다고 말하고 있습니다. 충분히 공감이 가는 내용입니다.
새롭게 시작하는 우리 앱도 앞서 설명한 3개의 계층 구조와 더불어 기능 기준이 된 형태를 같이 적용해 볼 생각입니다.