본문 바로가기

Personal Posting/Flutter

Flutter MVVM 구조 (Officially recommended by Google)

 

구글이 Flutter 앱 개발을 위한 MVVM(Model-View-ViewModel) 아키텍처를 공식적으로 권장한다고 발표했다. 이 발표는 현대적이고 유지보수가 용이하며 확장 가능한 애플리케이션을 구축하는 데 있어 MVVM의 중요성을 다시 한번 확인시켜주는 중요한 순간으로 평가되고 있다.

 

구글의 MVVM 아키텍처 공식 권장은 2024년 7월 11일, Flutter 3.27 버전 출시와 함께 발표되었습니다.

 

이번 블로그에서는 MVVM이 인기를 얻고 있는 이유를 알아보고, 기본 사항을 분석하며, Flutter 프로젝트에서 이 아키텍처를 구현하는 데 도움이 되는 자세한 폴더 구조의 예시를 제공해 보도록 한다.

 

왜 구글의 권장이 중요한가?

당연히 구글꺼니까 이번 구글의 MVVM 지원은 Flutter 개발자들에게 MVVM이 필수적인 아키텍처 패턴임을 확고히 해주었다고 생각한다. 구글의 공식적인 지지는 MVVM의 신뢰성을 높이고, 이를 더 널리 채택하도록 장려하며, MVVM이 견고한 애플리케이션을 구축하기 위한 모범 사례와 일치한다는 점을 개발자들에게 보장한다는 의미이다. MVVM은 개발 워크플로우를 단순화하고 유지보수를 용이하게 하며, 관심사의 분리를 촉진한다. 이는 오늘날의 애자일(Agile) 개발 환경에서 필수적인 요소들다.

 

참고

애자일(Agile) 개발 환경은 유연성, 협업, 반복적 진행, 그리고 변화에 대한 신속한 대응을 특징으로 하는 작업 환경을 의미한다. 이 환경은 전통적인 워터폴(Waterfall) 방식의 선형적이고 고정된 프로세스와는 달리, 지속적인 평가와 조정을 통해 프로젝트 목표를 달성하는 데 초점을 맞춘다.

 

MVVM 이란?

MVVM(Model-View-ViewModel)은 애플리케이션의 로직을 세 가지 주요 계층으로 분리하는 소프트웨어 디자인 패턴이다. 이 구조는 코드의 유지보수성과 테스트 가능성을 높이고, 애플리케이션의 확장성을 강화한다.

 

1. MVVM의 주요 구성 요소

  1) Model

    역할: 데이터와 비즈니스 로직을 관리다.

    특징:

      - 데이터 소스(예: 데이터베이스, API)에서 데이터를 가져오고 처리한다.

      - 애플리케이션의 Single Source of Truth 역할을 한다.

      - View나 ViewModel에 대한 의존성이 없다.

 

  2) View

     역할: 사용자 인터페이스(UI)를 담당하며 데이터를 사용자에게 표시한다.

     특징: 

      - 사용자의 입력을 처리하고 이를 ViewModel로 전달한다.

      - 비즈니스 로직은 포함하지 않으며, UI 렌더링에만 집중한다.

      - "더미 클래스(Dumb Class)"로 간주되며, 데이터나 로직을 직접 다루지 않는다.

 

  3) ViewModel

    역할: View와 Model 간의 중재자 역할을 한다.

    특징:

      - UI 로직을 처리하며, 데이터를 변환하여 View에 적합한 형태로 제공한다.

      - 상태(state)나 이벤트(event)를 노출하여 View가 이를 관찰할 수 있도록 한다.

      - 사용자 입력을 받아 Model과 상호작용하며, 필요한 경우 데이터를 업데이트한다.

 

2. MVVM의 장점

  1) 관심사의 분리(Separation of Concerns)

    - UI(View)와 비즈니스 로직(Model)을 분리하여 코드의 가독성과 유지보수성을 높인다.

    -  각 구성 요소가 독립적으로 개발 및 테스트될 수 있다.

 

  2) 테스트 용이성(Testability)

    - ViewModel은 UI(View)와 독립적이므로 단위 테스트(Unit Test)가 용이하다.

    - UI를 모방하지 않고도 비즈니스 로직과 데이터 처리를 검증할 수 있다.

 

  3) 유지보수성과 확장성(Maintainability & Scalability)

    - 코드가 구조화되어 있어 새로운 기능 추가나 변경이 쉽다.

    - 팀 협업 시 각 구성 요소를 독립적으로 작업할 수 있어 효율적이다.

 

  4) 재사용성(Reusability)

    - ViewModel은 특정 View에 종속되지 않으므로 다양한 View에서 재사용할 수 있다.

 

  5) 데이터 바인딩(Data Binding)

    - 데이터 바인딩 기술을 통해 View와 ViewModel 간의 실시간 동기화를 지원한다.

    - 수동으로 UI를 업데이트할 필요가 없어 개발 효율성이 증가한다.

 

3. MVVM의 작동방식

  MVVM은 각 구성 요소가 명확히 정의된 역할을 수행하며 상호작용한다.

  1) 사용자가 View에서 버튼 클릭 등의 동작을 수행하면, 해당 이벤트가 ViewModel로 전달된다.

  2) ViewModel은 Model과 상호작용하여 데이터를 요청하거나 업데이트한다.

  3) Model에서 처리된 데이터는 다시 ViewModel로 전달되고, ViewModel은 이를 변환하여 UI에 적합한 형태로 제공한다.

  4) 최종적으로 View는 이 데이터를 관찰(observe)하고 화면에 렌더링한다.

 

4. MVVM와 다른 아키텍쳐 패턴 비교

특징 MVC (Model-View-Controller) MVVM (Model-View-ViewModel)
중재자 역할 Controller ViewModel
관심사의 분리 수준 제한적 (View와 Controller간 결합 존재) 높음 (View와 Model 간 완전한 분리)
데이터 바인딩 지원 없음 양방향 데이터 바인딩 지원
테스트 용이성 낮음 높음
코드 재사용성 제한적 높음

 

5. Flutter에서의 MVVM 폴더 구조

lib/
├── data/
│   ├── network/
│   │   └── response/
│   │       └── app_exception.dart
│   ├── models/
│   └── repository/
├── resource/
├── util/
├── view/
├── view_model/
└── main.dart
  • data/network/response:
    API 응답을 처리하며, 네트워크 오류를 효과적으로 관리하기 위해 사용자 정의 예외(app_exception.dart)를 정의한다.
  • data/models:
    애플리케이션 전반에서 사용되는 데이터 모델을 포함한다. 예를 들어, Todo 모델은 할 일 항목의 구조를 정의할 수 있다.
  • data/repository:
    리포지토리 패턴을 구현하여 데이터 소스를 추상화한다. 이를 통해 ViewModel이 로컬 데이터베이스든 원격 서버든 단일화된 API를 통해 데이터를 상호작용할 수 있도록 한다.
  • resource:
    이미지, 폰트, 로컬라이즈된 문자열과 같은 정적 리소스를 저장한다.
  • util:
    애플리케이션 전반에서 사용되는 유틸리티 함수, 상수, 헬퍼(helper)들을 포함한다.
  • view:
    사용자 인터페이스(UI)를 렌더링하는 화면(screen) 및 위젯(widget)과 같은 UI 구성 요소를 포함한다.
  • view_model:
    UI 로직과 상태를 관리하는 ViewModel 클래스를 구현한다. 이 클래스들은 View에 데이터를 노출하고 사용자 상호작용에 응답한다.
  • main.dart:
    애플리케이션의 진입점으로, Provider나 Get과 같은 의존성 주입 설정과 초기 설정을 구현한다.

6. MVVM 패턴으로 To-Do 앱을 예제로 만들어보자.

  1) Model

class Todo {
  final String id;
  final String title;
  final bool isCompleted;
  Todo({required this.id, required this.title, this.isCompleted = false});
}

 

  2) ViewModel

import 'package:flutter/foundation.dart';
import '../models/todo.dart';
class TodoViewModel extends ChangeNotifier {
  List<Todo> _todos = [];
  List<Todo> get todos => _todos;
  void addTodo(String title) {
    _todos.add(Todo(id: DateTime.now().toString(), title: title));
    notifyListeners();
  }
  void toggleTodoStatus(String id) {
    final index = _todos.indexWhere((todo) => todo.id == id);
    if (index != -1) {
      _todos[index] = Todo(
        id: _todos[index].id,
        title: _todos[index].title,
        isCompleted: !_todos[index].isCompleted,
      );
      notifyListeners();
    }
  }
}

 

  3) View

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../view_model/todo_view_model.dart';
class TodoScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final viewModel = Provider.of<TodoViewModel>(context);
    return Scaffold(
      appBar: AppBar(title: Text('MVVM To-Do App')),
      body: Column(
        children: [
          Expanded(
            child: ListView.builder(
              itemCount: viewModel.todos.length,
              itemBuilder: (context, index) {
                final todo = viewModel.todos[index];
                return ListTile(
                  title: Text(todo.title),
                  trailing: Checkbox(
                    value: todo.isCompleted,
                    onChanged: (_) {
                      viewModel.toggleTodoStatus(todo.id);
                    },
                  ),
                );
              },
            ),
          ),
          Padding(
            padding: const EdgeInsets.all(8.0),
            child: TextField(
              onSubmitted: (value) => viewModel.addTodo(value),
              decoration: InputDecoration(
                labelText: 'Add To-Do',
                border: OutlineInputBorder(),
              ),
            ),
          ),
        ],
      ),
    );
  }
}

 

7. 결론

MVVM은 현대 애플리케이션 개발에서 널리 사용되는 아키텍처 패턴으로, 특히 복잡한 UI를 가진 애플리케이션에서 큰 장점을 제공한다. 관심사의 분리를 통해 코드베이스를 더 체계적으로 관리하고, 유지보수성과 테스트 용이성을 극대화한다. Flutter와 같은 프레임워크에서도 MVVM은 강력한 선택지로 자리 잡고 있으며, 이번 구글의 발표로 이는 더욱 확실해 졌다. 앞으로도 MVVM 패턴은 효율적이고 확장 가능한 애플리케이션 개발에 적합한 구조를 구현하고 싶을 때 사용될 것으로 보인다.

 

아래 링크의 포스팅을 참고하여 정리한 내용입니다. 원문을 확인하고 싶으시면 아래 링크를 확인해주세요.

출처 - https://medium.com/@ksufi7350/mvvm-officially-recommended-by-google-for-flutter-development-ba17f899d320