Flutter를 공부하다 보면 어느 순간부터 UI 위젯을 넘어서 "아키텍처"에 대해 고민하게 돼요. 작은 앱에서는 모든 코드가 하나의 파일에 있어도 별문제 없지만, 기능이 늘어나고 팀 프로젝트가 되면 유지보수와 확장성에서 문제가 생기기 시작하거든요. 그래서 저처럼 Flutter를 처음 시작하고 나서 조금씩 실력을 쌓아가는 학습자들에게 공식 문서에서 제공하는 앱 아키텍처 가이드는 필수 참고서예요.
이번 글에서는 Flutter 공식 문서의 Guide to app architecture 내용을 바탕으로, Flutter 앱을 어떻게 구조화할 수 있는지, 어떤 원칙을 따르는 것이 좋을지에 대해 정리해 보려고 해요. 다소 복잡하게 느껴질 수 있는 구조도 실제 사례를 상상하면서 설명할게요. 지금 Flutter 앱 구조에 대해 막연한 고민을 하고 있는 분들이라면, 이 글이 방향을 잡는 데 도움이 될 수 있을 거예요.
구조의 핵심은 역할 분리(Separation of Concerns)
Flutter 공식 문서에서 가장 먼저 강조하는 건 역할 분리, 즉 Separation of Concerns예요. 앱을 만들다 보면 데이터, UI, 로직이 뒤섞이기 쉬운데, 이걸 명확히 구분해야 나중에 확장하기도 쉽고 테스트하기도 편해져요. Flutter 앱은 기본적으로 두 개의 큰 층으로 나눌 수 있어요: UI Layer와 Data Layer예요.
UI Layer는 사용자와 직접 상호작용하는 부분으로, 우리가 흔히 만드는 화면, 버튼, 리스트 같은 것들이 여기에 해당돼요. 이 레이어는 다시 View와 ViewModel로 나뉘어요.
- View는 위젯 조합으로 화면을 그려주는 역할을 해요. 단, 여기에는 복잡한 로직이 들어가면 안 돼요. 단순한 조건문이나 레이아웃 계산 정도만 허용돼요.
- ViewModel은 View가 보여줘야 할 상태를 정리해주고, 사용자 인터랙션에 따라 적절한 처리를 하죠. 예를 들어 버튼 클릭 시 어떤 함수를 실행할지 결정하거나, 여러 데이터 소스를 조합해서 UI에 보여줄 데이터를 만들어주는 역할을 해요.
이 둘은 보통 1:1로 짝을 이루며, 하나의 기능 단위를 담당해요. 예를 들어 로그인 기능이 있다면 LoginView와 LoginViewModel이 함께 구성돼요. 이런 구조는 흔히 MVVM(Model-View-ViewModel)이라고 불리는 아키텍처 패턴에서 온 거예요.
UI Layer는 "보여주기"와 "상호작용 반응"에 집중하고, 데이터는 ViewModel이 책임지도록 구조를 짜면 훨씬 명확하고 관리하기 쉬운 코드가 돼요.
Data Layer, 앱의 ‘진짜 내용’을 책임지는 구조
앞서 살펴본 UI Layer가 화면과 상호작용을 담당한다면, Data Layer는 앱이 실제로 다루는 정보와 로직을 책임져요. 이 레이어는 사용자의 눈에 직접 보이지 않지만, 앱의 핵심 동작을 뒷받침하는 매우 중요한 부분이에요. Flutter 공식 문서에서는 이 레이어를 Repository와 Service라는 두 구성요소로 설명하고 있어요.
먼저 Repository(레포지토리)는 말 그대로 앱 데이터의 중심, 즉 ‘진실의 원천’이에요. API를 통해 받아온 데이터, 캐시된 정보, 또는 로컬 저장소에서 읽어온 데이터를 가공해서 앱이 사용할 수 있는 형태로 제공해줘요. 예를 들어 UserProfileRepository는 로그인된 사용자의 프로필 정보를 가져오고, 이 데이터를 ViewModel이 받아 화면에 표시할 수 있도록 도와주는 거죠.
Repository는 다음과 같은 일을 담당해요.
- 다양한 Service에서 데이터를 받아와 통합하기
- 캐싱 및 오류 처리
- 새로고침, 재시도 로직
- 외부 요청이 실패했을 때 대체 데이터 제공 등
이렇게 Repository가 다양한 책임을 떠맡고 있기 때문에, 코드의 재사용성과 테스트 가능성이 크게 향상돼요. 똑같은 데이터를 여러 화면에서 쓰더라도 Repository만 잘 만들어두면 중복 코드를 줄일 수 있고, 테스트할 때도 외부 API에 의존하지 않고 쉽게 테스트할 수 있어요.
그럼 Repository가 데이터를 어디서 가져오느냐? 바로 Service(서비스)를 통해서예요.
Service는 Flutter 앱에서 외부 세계와 연결되는 가장 바깥쪽 레이어예요.
- REST API 요청
- 로컬 파일 접근
- 플랫폼 기능 (예: GPS, 카메라, 알림 등)
이런 모든 외부 데이터를 가져오는 역할을 하는 것이 바로 Service예요. 중요한 점은, Service는 상태를 가지지 않고 단순히 데이터를 요청하고 결과를 반환하는 역할만 한다는 거예요. 예를 들어 UserApiService는 사용자 정보 API를 호출하고, 그 결과를 UserRepository에 전달하는 식이에요.
정리하면, Service는 데이터를 "가져오기만" 하고, 그 데이터를 어떤 형태로 쓸지는 Repository가 결정해요. 이렇게 책임을 나누면 각 역할이 명확해지고, 코드를 관리하고 테스트하기 쉬워져요.
또 하나 중요한 포인트는 Repository와 Service는 서로 유기적으로 연결되면서도, 각자의 책임이 명확히 분리되어 있어야 한다는 점이에요. Repository는 여러 Service를 조합할 수 있고, 하나의 Service가 여러 Repository에서 재사용될 수도 있어요. 이 유연한 관계 덕분에 앱 구조가 커져도 복잡하지 않고 확장하기 쉬운 구조를 만들 수 있어요.
도메인 레이어: 복잡한 로직을 다루는 중간자
앱이 커지고 기능이 다양해지면, ViewModel에 너무 많은 로직이 몰리는 문제가 생길 수 있어요. 이럴 때 사용하는 게 도메인 레이어(Domain Layer)예요. 이 레이어는 UI와 데이터 사이에서 복잡한 비즈니스 로직을 중간에서 처리해주는 역할을 해요.
도메인 레이어에서는 주로 Use-case(또는 Interactor)라는 클래스를 정의해요. Use-case는 말 그대로 ‘특정 기능을 수행하는 하나의 명확한 작업 단위’를 의미해요. 예를 들어 "사용자 프로필 불러오기", "로그인 처리하기", "장바구니에 상품 추가하기" 같은 것들이 대표적인 Use-case죠.
Use-case가 필요한 상황은 다음과 같아요.
- 여러 Repository에서 데이터를 가져와 조합해야 할 때
- 로직이 너무 복잡해서 ViewModel 안에 두기 어려울 때
- 동일한 로직이 여러 ViewModel에서 반복 사용될 때
도메인 레이어를 추가하면 코드의 재사용성, 테스트 가능성, 가독성이 높아지는 장점이 있어요. 반면, 클래스 수가 늘어나고 구조가 복잡해지는 단점도 있죠. 그래서 공식 문서에서도 말하듯 꼭 필요한 경우에만 도입하는 걸 추천하고 있어요. 처음부터 무조건 넣기보다는, ViewModel이 과도하게 복잡해질 때 자연스럽게 도입하는 방식이 현실적이에요.
예를 들어 ViewModel에서 두 개 이상의 Repository 데이터를 조합해 복잡한 조건으로 필터링하고 가공해야 한다면, 그 작업을 Use-case로 옮겨보는 거예요. ViewModel은 단순히 이 Use-case를 호출만 하면 되고, 그만큼 구조가 깔끔해져요.
마치며...
Flutter 앱의 구조를 처음 접하면 다소 생소하고 복잡하게 느껴질 수 있어요. View, ViewModel, Repository, Service, Use-case… 이름도 많고, 서로 어떻게 연결되는지 감이 잘 안 올 수도 있죠. 하지만 구조의 본질은 단순해요. 각 컴포넌트가 자신의 역할에만 집중하도록 코드를 나누는 것, 바로 그게 Flutter 아키텍처 가이드가 말하고자 하는 핵심이에요.
처음에는 View와 ViewModel만 나누는 것부터 시작해보세요. 점점 프로젝트가 커지면 Repository를 도입하고, 필요하다면 Use-case로 복잡한 로직을 분리하면서 구조를 확장해 나가면 돼요. 중요한 건 이 아키텍처가 "정답"이 아니라 가이드라인이라는 점이에요. 팀의 상황이나 개인의 스타일에 맞게 유연하게 적용해도 괜찮아요.
Flutter 앱을 더 안정적이고, 테스트 가능하고, 유지보수하기 쉬운 구조로 만들고 싶다면, 이번 공식 문서 기반의 구조 가이드는 꼭 한 번 찬찬히 읽어보길 추천해요. 저 역시 이 가이드를 통해 Flutter 앱을 한층 더 깊이 있게 이해하고, 더 깔끔하게 만들 수 있게 되었거든요.
공부하는 여정 속에서 구조에 대한 고민은 피할 수 없는 단계예요. 그 고민에 이 글이 작은 이정표가 되길 바랄게요!
'IT' 카테고리의 다른 글
플러터 앱 개발, 중요한 점 복습하기 (0) | 2025.04.22 |
---|---|
REST API 한 큐에 이해하기 (0) | 2025.04.21 |
앱 UI 구현, 무엇부터 시작해야 할까요? (0) | 2025.04.18 |
[항해플러스 | 항해99] 1인 개발자를 위한 백엔드 부트캠프, 할인코드 있어요! (2) | 2025.04.17 |
채팅 기능이 필요할 땐 Socket (2) | 2025.04.17 |