어떤 프로젝트여도 시작할 때 가장 중요하게 생각해야 하는 점은 상태관리 패키지에 대해서 생각을 해야합니다. 상태관리 패키지를 어떤걸 선택하냐에 따라 보통 다른 아키텍처를 가져가거나 폴더 구조가 정해지기 때문입니다.
소규모 : stateful 위젯의 setState와 provider만 이용하여 개발을 할 경우 초기, 엄청 작은 규모의 앱일 경우 관리하기가 쉽습니다. 러닝커브도 낮고, 원하는 위젯에 들어가면 모든 로직이 다 들어있고, 프로바이더를 통해 전역 상태관리만 해주면 금방 앱을 만들 수 있습니다. MVP 버전의 개발일 경우에 괜찮을 것 같습니다. (MVC 패턴으로 갈 때 추천)
중규모 : 플러터에서는 보통 RiverPod, GetX, Bloc을 가장 많이 사용하는데, 이 중에 무엇이 가장 좋을지에 대해 많은 말들이 있지만 모두 훌륭한 상태관리 패키지이기 때문에 프로젝트 규모, 개발팀의 기호에 따라 정하시면 됩니다. (MVVM, 클린아키텍처 혼합 추천)
대규모 : RiverPod, GetX, Bloc 모두 추천합니다.
대규모에서는 중급자 이상일 것이기 때문에 꼭 상태관리의 핵심을 기억하며 적용해야합니다. 상태관리의 핵심은 View와 Controller 영역의 코드들을 효율적으로 관리되도록 해야합니다. 플러터 위젯들을 효율적으로 분리하고 필요한 위젯에서만 api 호출과 리렌더링이 이루어지도록 하고 전역적으로 필요한 경우에만 전역으로 빼서 상태관리 하는 방식의 코드 설계 및 작성이 필요합니다. 이렇게 하지 않았을 경우 한 컨트롤러에서 하는 역할이 많아져서 어떤 위젯에서 어떤 api가 필요하고 상태관리는 어떻게 이루어지고 있는지 파악하기 어려워집니다.
가장 대중적인 MVC 패턴, MVVM 패턴, 클린 아키텍처 중에 고르려면 프로젝트의 규모를 알아야 합니다.
추천 드리는 방식은 아래와 같습니다.
소규모 : MVC 패턴
중규모 : MVVM 패턴, 클린 아치텍처
대규모 : MVVM 패턴, 클린 아치텍처
소규모에서는 추후 확장성을 생각하지 않아도 될 경우 MVC를 사용하면 되고 MVC 내에서만 동작하도록 코드를 작성하면 됩니다.
중규모, 대규모에서는 추후 확장성을 생각해야 하고 관리하기 쉽고 관심사가 분리 되고 종속성 주입이 되어야 하기 때문에 MVVM 패턴, 클린 아치텍처로 가는걸 권장합니다. 만약 러닝커브 없이 빠르게 개발을 들어가야 한다면 MVVM 패턴 으로 잡고, 러닝커브가 상관없으신 분들은 클린 아키텍처를 적용하면 됩니다. 하지만 둘 중 하나의 패턴만 적용할 경우 다음과 같은 문제에 직면할 수 있습니다.
MVVM 패턴 사용할 경우 겪을 수 있는 문제 : api 호출을 ViewModel에서 작성하면 비즈니스 로직 및 앱로직이 다 작성 될 것입니다. 이렇게 된다면 도메인 및 데이터 레이어의 구분이 명확해지지 않습니다. 도메인의 역할에는 데이터를 서버에서 또는 로컬 등에서 받아와 뷰로 전달해야 하는데 이 때 비즈니스 로직과 데이터 레이어의 역할까지도 함께 코드가 작성되기 때문에 관심사가 명확하게 구분이 안되어 유지보수 및 단위테스트를 작성하는데에 어려움을 겪을 수 있습니다.
클린 아키텍처를 사용할 경우 겪을 수 있는 문제 : View를 어떻게 나누고 컨트롤러를 어떻게 나눌지 명확한 가이드라인이 없습니다. 따라서 MVC 패턴에서 사용하는 뷰와 컨트롤러 영역을 가져갈 수 있고 MVVM에서 사용하는 뷰와 뷰모델과의 관계처럼 가져갈 수 있습니다. 만약 MVC 패턴처럼 가져간다면 한 컨트롤러에서 하는 역할이 너무 많아져서 추후 유지보수에 어려움을 겪을 수 있습니다. 만약 MVVM 패턴처럼 가져간다면 클린 아키텍처에서는 가이드를 주지 않기 때문에 어떻게 위젯들을 나누고 뷰모델의 범위를 어디까지 정하는 것이 맞는지에 대한 고민이 생길 것입니다. 또한 어떤 곳에서는 MVC패턴의 뷰와 컨트롤러 영역처럼 코드를 구현하고 어떤 곳에서는 MVVM에서 사용하는 뷰와 뷰모델의 관계처럼 섞으면서 사용한다면 협업할 때 어떻게 짜는게 옳은 것인지 의문이 생길 것입니다.
결국에는 초기에 아키텍처를 설계할 때 클린아키텍처 + MVVM을 가장 추천드립니다. MVVM은 클린 아키텍처에서 View와 View모델을 controller와 Presentation 계층으로 사용하고 유즈케이스부터는 종속성 주입과 함께 클린아키텍처 방식대로 구현하는걸 추천드립니다. 더불어 아토믹 패턴을 사용하면 플러터 위젯의 정의 방법에 대해서 명확하게 구분할 수 있기 때문에 아토믹 패턴 적용도 추천드립니다.
더해서 controller(ViewModel) 계층은 서버에서 내려주는 api를 기준으로 분리, 앱 로직(UI 관련해서 변경하거나 변경되는 로직)별로 분리하는 것을 추천드립니다. 예를 들어 한 화면에서 graphql 쿼리를 사용하여 하나의 페이지 데이터 전체를 가져온다면 하나의 컨트롤러에서 받아와 View에 뿌려줍니다. 그 View는 해당되는 데이터를 받아왔을 때 해야하는 로직들을 처리하는 ViewModel이 있을 것입니다. 그 ViewModel에서 처리해줍니다. 최상단 ViewModel은 해당 페이지만의 전역 상태 관리, 컨트롤러의 역할이고 View에서 나눠진 ViewModel은 지역 상태 관리, 컨트롤러 역할을 합니다. 지역 상태관리 ViewModel은 서버 api를 받아오는 역할을 하거나 앱 로직을 처리하는 일을 수행할 수 있습니다.
아키텍처를 정했다면 정한 아키텍처를 사용한 플러터 레포 예시들을 보며 우선 기본적인 폴더 구조를 잡아야 합니다. 각 계층에 맞는 폴더들을 작성하고 각 폴더(계층)들에 맞는 파일들만 작성을 해야 합니다.
뼈대가 되는 폴더들을 만들어 구조를 잡았다면 global을 관리하는 폴더에 가서 디자이너와 함께 정한 TextStyle들, 기본 위젯들(버튼, 텍스트, 리스트 등), 전역 Theme 들을 개발 과정에서 재사용할 수 있도록 잡아놓습니다. 만약 디자이너와 협의가 안되어 있다면 언제라도 바꾼 전역 스타일을 적용할 수 있도록 미리 뼈대로 잡아놓습니다. 이렇게 될 경우 같은 버튼인데, 버튼이 사용되는 곳마다 다른 스타일을 가져가거나 수정할 때 사용되는 모든 곳을 수정해야 하는 것을 막을 수 있습니다.
가장 이상적인 것은 디자이너와 함께 Global한 공통 위젯들을 정의하고 개발을 하는 것입니다. 디자인 시스템 관련해서 디자이너와 함께 소통하고 사용할 textTheme, 전반적인 Theme들을 미리 적용합니다. 그리고 이에 벗어나지 않도록 디자인 하도록 요청합니다. 벗어나는데 꼭 필요한 디자인이라면 디자인 시스템에 등록하면 됩니다. 플러터 위젯북을 사용해서 디자이너가 원하는 공통 위젯이 맞는지 검증하거나 적용할 수도 있습니다. 하지만 모든 개발 회사가 미리 이런걸 생각하지 않고 개발했을 수도 있으니 조금씩 디자이너와 함께 Global한 공통 위젯들을 정의하고 개발을 진행하면 됩니다.
전역적인 모든 뼈대가 완성이 되었다고 생각이 들면 데이터 레이어부터 코드를 작성 해봅니다. 인터페이스를 사용하여 테스트 환경에 대한 서비스를 구현하고 실 환경에서 사용할 서비스들을 구현합니다.그리고 실제 api를 적용해봅니다. 그리고 api들의 경우 서버에서 내려주는 여러 상태코드에 따라 전역적으로, 지역적으로 에러핸들링을 어떻게 할지, 테스트 코드들은 어디에 위치시키고, 테스트의 범위는 api 하나씩 할지 등을 미리 러프하게 룰들을 정의하고 이후 실제 기능들을 개발하며 수정해야겠다고 정해지는 룰들에 대해 팀원들과 상의하고 수정하면서 개발합니다. 그 이후에는 Flavor를 나눠 dev, stg, prod 등 기업에 맞는 개발 환경을 나눕니다. 그리고 어떤 서버 통신 패키지로 개발을 할지, 로컬 스토리지는 어디로 할지 등에 대해 정합니다.
전역적인 룰들이 정해지면 도메인을 분석해 개발에 들어가면 되고, 기능 개발을 할 때 아키텍처와 폴더 구조에 벗어나는 코드는 코드리뷰를 통해 해결합니다. 그리고 만약 아키텍처나 폴더 구조를 수정해야 할 상황이 생길 때 팀원들과 공유하여 그 방법에 대해 올바른지에 대해 상의하여 결정해야 합니다.
아키텍처와 폴더 구조를 잡아도 리팩토링은 개발에 있어서 꼭 적용 되어야 하는 부분입니다. 지속적인 디자인 패턴, 객체지향 원칙, 알고리즘 등을 학습하며 지역적으로 코드에서 더 낫게 수정할 수 있는 부분들이 있거나 구조적으로 수정이 필요한 경우가 생긴다면 따로 시간을 빼서 리팩토링을 해야합니다.