플러터의 공식문서에서 앱 아키텍처를 정의한 문서를 보았습니다. 플러터도 당연히 메인 아키텍처가 있을 테고 이를 안드로이드 앱 아키텍처처럼 공식에서 권장하기도 하네요. 물론 주변 사람들의 얘기를 들어보면 다양한 아키텍처를 사용하고 있는 것 같긴 해서 역시 정해진 정답은 없다고 생각합니다.
참고로 제가 이번에 정리할 내용은 플러터의 구조를 정의한 플러터 구조 아키텍처가 아니라, 플러터 코드를 깔끔하게 작성하기 위해 정의된 플러터 앱 아키텍처 설계입니다. 클린 아키텍처같은 구조를 의미합니다.
참고할 공식 문서는 아래와 같습니다.
Architecting Flutter apps
Learn how to structure Flutter apps.
docs.flutter.dev
기본 구조

Data Layer <-> (Domain Layer) <-> UI Layer 로 구성되어 있는 안드로이드와 동일하게 2단계 필수 계층에 생략 가능한 중앙 계층으로 구성되어 있습니다. 중앙에 있는 Logic Layer를 제외하면 이름조차 똑같네요. 아마 같은 구글에서 적용하고 설명하는 아키텍처라 그럴 것 같습니다.
공식 문서에서 중요한 기본 구조로 관심사 분리를 얘기하고 있는데, 이는 안드로이드나 클린 아키텍처와 동일합니다. 제가 이전에 작성했던 아키텍처 설명에 관심사 분리는 아래와 같이 정리했습니다.
관심사 분리란 크게 각 섹션을 계층화 혹은 캡슐화 시켜 다른 섹션과 공유하지 않은 상태를 유지하는 것을 의미합니다. 이는 각 계층이 분리되어 서로가 서로의 계층을 침범하지 않은 상태로 합의된 input - output을 공유하는 것으로 정의됩니다.
이 설명은 위에서 보이는 사진처럼 같이 각 레이어들이 서로의 영역을 침범하지 않고 각자가 정의된 방식에 따라 레이어끼리 통신하듯 구성하는 방식을 의미합니다.
그리고 또 다른 개념으로는 SSOT(Single Source of Truth)라는 개념이 있습니다. 한글로는 단일 소스 저장소라고도 번역되는데요. 제가 작성한 안드로이드 앱 아키텍처에서도 동일하게 중요한 부분이어서 설명한 부분이 있습니다.
SSOT(Single-Source Of Truth)
앱에서 새로운 데이터 유형을 정의할 때는 데이터 유형에 단일 소스 저장소(SSOT)를 할당해야 합니다. SSOT는 데이터의 소유자이며, SSOT만 데이터를 수정하거나 변경할 수 있습니다. SSOT는 이를 위해 불변 유형을 사용하여 데이터를 노출하며, 다른 유형이 호출할 수 있는 이벤트를 수신하거나 함수를 노출하여 데이터를 수정합니다.
단일 소스 저장소 라고 번역되어 있는 SSOT는, 말 그대로 데이터 처리를 일원화하는 것을 의미합니다. 특정 데이터는 특정 저장소에서만 처리한다는 것인데요.
- 특정 유형 데이터의 모든 변경사항을 한곳으로 일원화합니다.
- 다른 유형이 조작할 수 없도록 데이터를 보호합니다.
- 데이터 변경사항을 더 쉽게 추적할 수 있도록 합니다. 따라서 버그를 발견하기가 쉬워집니다.
이 패턴의 이점으로 나열된 부분들을 확인해보면 SSOT는 Clean Architecture의 DataSource부분을 의미하는 것 같습니다. 애초에 다른 아키텍처니 정확하게 매칭되지는 않겠으나, 서로가 어느정도 유사점을 보이는 관계를 생각해보았을 때 특정 데이터의 유형(유저에 대한 정보 등)이라면 특정 Class(유저 정보를 다루는 DataSource, Repository등)를 통해 get, set 되어야 한다는 것을 의미합니다.
하지만 이 부분은 어떤 파트에 적용하느냐에 따라 조금씩 다른데요. DBA가 사용할 땐 DB의 정책을, Android의 경우 위와 같이, 또 Swift나 백엔드로 넘어가면 조금씩 다르게 적용되는 것 같습니다.
위와 같이 설명해두었습니다. 조금 재밌는 부분은 UDF(Unidirectional data flow)가 구조로서 설명되어 있는 부분이었습니다. 아래와 같은 이미지를 통해 UDF를 설명해두었는데, 안드로이드 앱 아키텍처나 클린 아키텍처에서도 충분히 사용하고 권장하지만 구조로서 설명하지는 않았던 것 같아서 신기했습니다.

위의 이미지를 보면 UI Layer가 Logic Layer에게 Events를 통해서 데이터를 주고 다시 돌려받는 과정이 있습니다. 저도 안드로이드에서 클린 아키텍처를 사용할 때 유저의 클릭 이벤트나 상호작용은 handleEvent 메소드로 처리하고 다시 Logic layer에서 전달하는 데이터가 UI의 상호작용을 일으키는 경우 action으로 처리하고 있는데, 디테일한 사용 방식은 각자가 원하는 방향대로 진행하면 될 것 같습니다. 한 번 UDF 형태로 작성하다보면 이 구조가 너무 쉬워서 포기하지 못하게 되는데 아예 공식 아키텍처에서 추천하고 있으니 굉장히 편할 것 같습니다.
UI 레이어
UI 레이어는 크게 View - ViewModel 형태의 두 단위로 구분됩니다. 다른 구조를 사용할 수 없다는 것은 아니지만 플러터 앱 아키텍처의 공식 문서는 MVVM 모델을 추천하고 있습니다. 여기서 View는 플러터에서 사용자와 상호작용하는 눈에 보이는 모든 Widget으로 만든 화면을 의미합니다. 이 Widget에는 비즈니스 로직이 들어가면 안됩니다. 무거운 계산이나 repository or UseCase 호출 등의 과정은 전부 ViewModel에서 이루어져야 합니다. 기본적인 MVVM의 이론을 따르고 있다고 생각하시면 되겠습니다.

공식 문서에서 UI 레이어를 소개할 때 MVVM 모델과 조금 다른 부분이 있다면 View - ViewModel이 1:1 대응이라고 설명하는 부분일 것 같습니다. MVVM 패턴은 의견이 분분한 것 같지만 꼭 View - ViewModel이 1:1로 대응되어야 한다고 설명하고 있진 않기 때문에 이 부분에서 의견이 갈라질 수 있겠습니다.
https://docs.flutter.dev/app-architecture/case-study/ui-layer
UI layer case study
A walk-through of the UI layer of an app that implements MVVM architecture.
docs.flutter.dev
Data 레이어
공식 문서에서는 거의 Logic Layer를 생략한 것을 전제로 이야기를 합니다. 문서 하단에 보면 Logic 레이어가 추가된 상태의 설명도 있지만, 'MVVM 용어로 모델 이라고 불리는 애플리케이션의 데이터 계층은 모든 애플리케이션 데이터의 원천입니다. 원천으로서 애플리케이션 데이터는 오직 이곳에서만 업데이트되어야 합니다.' 같은 문구도 있는 것을 보아 기본적으로는 UI 레이어와 Data 레이어가 직접적으로 연결되는 것을 전제로 합니다.

상단 이미지의 우측이 Data Layer 입니다(그림에도 잘 표현되어 있지만...). 클린 아키텍처는 기본적으로 Repository의 인터페이스가 Domain Layer 계층에 존재하고 있지만, 이 경우 Data Layer에서 Repository의 인터페이스와 구현부를 따로 설정할 필요까지는 없어 보입니다. 볼륨이 작다면 그냥 Repo 클래스 하나로 정리해도 무리는 없어 보입니다.
위 이미지의 Service는 안드로이드의 Retrofit처럼 Http 통신을 위한 클래스를 표현한 것 같습니다. 실제 공식문서상으로도 API와 상호작용하는 상태 비저장 Dart Class라고 표현하고 있습니다.
https://docs.flutter.dev/app-architecture/case-study/data-layer
Data layer
A walk-through of the data layer of an app that implements MVVM architecture.
docs.flutter.dev
Logic 레이어 (선택사항)
여긴 공식문서에서 따로 섹션을 나눠 설명해주고 있진 않네요. 전체 구조 이미지를 보며 Logic 레이어를 생각하면 좋을 것 같습니다. 참고로 여기서 Logic Layer는 생략이 가능하다는 점도 안드로이드 앱 아키텍처와 거의 유사하다는 것을 확인할 수 있습니다. 안드로이드 개발자분들이 플러터를 하실 때 아키텍처로 고생할 일은 없을 것 같습니다.

여기서는 UseCase만이 로직 레이어에 속해 있는데, 아마 양방향으로 화살표가 표시되어 있으니 주로 Repository의 interface 같은 클래스들이 속해있게 될 것 같습니다.
공식문서를 살펴볼수록 안드로이드 앱 아키텍처와 비슷한 구조로 플러터 앱을 만들기 위한 노력이 숨어있다고 생각이 됩니다. 구글에서는 안드로이드 앱은 어떤 코드구성이든 구조를 유지하는 것을 원하는 것으로 보입니다(아님말고). 요새 플러터 앱을 조금 만들어보고 있는데, 아무래도 구조를 비슷하게 가져가니 적응이 좀 쉽더라구요. 언어적인 적응만 하면 되니 러닝커브가 낮아지는 느낌이었습니다.
플러터를 오래 개발하신 분들이 어떤 아키텍처로 개발하는지는 잘 모르겠습니다만, 공식문서에서 추천해주는 아키텍처를 사용하고 있는 분들도 꽤 많으시겠죠...? (제가 플러터로 밥 벌어먹고 살 일은 없을 것 같으니 저는 열심히 공식을...)
'크로스플랫폼 > 플러터' 카테고리의 다른 글
| 플러터 앱 아이콘 적용 (5) | 2025.08.11 |
|---|---|
| Flutter란? (1) | 2025.06.13 |
댓글