Flutter Multi-Package Architecture

플러터로 멀티 패키지 아키텍처를 설계해보자.

Doohyeon Kim
Doohyeon.kim
9 min readFeb 18, 2023

--

전에 Client-Side Clean Architecture에 대해 작성한 적이 있었다. 그 때 잠깐 Multi-Package Architecture에 대해 언급한 적 있었다. 이번 포스트에서 Multi-Package Architecture에 대해 작성한다.

Package와 Module

Multi-Package Architecture와 Multi-Module Architecture(Modular Archirtecture)는 다른 개념이다.

많은 개발자들이 Multi-Package Architecture와 Multi-Module Architecture를 같은 개념으로 생각한다. 프레임워크마다 모듈과 패키지의 정의가 다르기 때문에 헷갈릴 수 있다. Python과 Java만 봐도 패키지, 모듈에 대한 정의를 반대로 하고 있다. 파이썬은 모듈의 모음이 패키지인데 반해, 자바에서는 패키지의 모음이 모듈이다. 게다가 멀티 패키지와 멀티 모듈은 모두 코드를 구성하는 방식에서 모듈화를 지향하기 때문에 헷갈릴만 하다.

참고로 로버트 마틴은 클린 소프트웨어에서 크기와 상관 없이 클래스나 패키지, 라이브러리와 같은 임의의 요소라고한다. 즉, 모듈이 패키지를 포함하는 개념이다.

모듈과 패키지에 대해서 딱히 정의하고 싶진 않다.

다만, 이 글에서 패키지는 코드의 단순한 묶음이고, 모듈은 독립적인 기능 단위로서 빌드, 배포, 테스트 가능하도록 구성된 것이라고 이해하면 된다.

멀티 패키지 아키텍처와 멀티 모듈 아키텍처 모두 큰 규모의 애플리케이션에서 소프트웨어를 구성하기 위한 방법론이다. 그러나 두 가지 아키텍처는 구성 방법과 구성 요소의 관계에서 차이가 있다.

멀티 패키지 아키텍처는 모든 코드를 하나의 프로젝트에 모아 놓고, 코드를 패키지별로 나누어 관리하는 방법이다. 패키지는 관련된 기능을 담당하고, 프로젝트 내에서 서로 의존성이 있을 수 있다.

멀티 모듈 아키텍처는 여러 개의 모듈로 나누어진 소프트웨어 시스템이다. 각 모듈은 독립적인 소스 코드를 가지고 있으며, 서로 다른 모듈 간에는 의존성이 존재할 수 있다. 이러한 모듈은 일반적으로 빌드, 배포, 테스트 및 유지 보수를 단순화하는 데 도움이 된다.

즉, 멀티 패키지 아키텍처는 코드를 관리하는 방법이고, 멀티 모듈 아키텍처는 코드를 구성하는 방법이다. 멀티 모듈 아키텍처는 보다 복잡한 애플리케이션에서 모듈 간의 결합도를 낮추고 유연성을 높이는데 유용하다.

멀티 패키지 아키텍처는 보다 더 feature와 코드 관리에 중심을 둔 아키텍처라면, 멀티 모듈 아키텍처는 코드의 재사용성과 협업, 그리고 배포 관리에 중심을 둔 아키텍처다.

참고로 Flutter는 package에 대해 다음과 같이 정의 한다.

Packages enable the creation of modular code that can be shared easily.

그리고 아래는 flutter -h를 통해 나오는 설명이니 참고바란다.

Multi-Package Architecture는 클린 아키텍처처럼 개발자 필독서 수준으로 퍼진 개념이 아니기 때문에, 설계하는 사람의 상황과 판단에 따라 다를 수 있다.

내가 Multi-Pakcage Architecture를 사용했던 이유는, 회사에서 맡은 아이템이 기능이 너무 많아서 모놀리식으로 관리하기에는 부담이 있었다. 팀 규모가 컸으면 Multi-Module Architecture를 사용했을텐데, 팀 규모가 작아서 Multi-Package Architecture를 사용했다.

Multi-Package Architecture

다이어그램이 많이 복잡해질 것 같아, 패키지 간 의존성 관계는 표시하지 않았다. 각 패키지들은 개별적으로 관계를 맺을 수 있다.

회색으로 처리된 Directory는 멀티 패키지 아키텍처와 상관이 없다. Monorepo를 위한 것이며, Monorepo는 나중에 따로 작성하려 한다.

Apps

애플리케이션을 의미한다.

비슷한 기능과 데이터를 사용하는데, 앱이 여러개로 나뉘는 경우에 유용하다. 모바일 카톡 PC 카톡과 같이, 같은 서비스지만 제공하는 플랫폼이 다를 때 사용할 수 있다.

사실 앱을 여러개로 나누면 멀티 모듈의 개념이 조금 들어온 것인데, 이 부분은 멀티플랫폼을 지원하는 Flutter라서 가능한 것이다.

내가 설계했던 서비스의 경우 같은 서비스를 모바일, 웹, 키오스크 형태로 제공해야 했고, 기능도 일부 달랐기 때문에 각 플랫폼에 맞춰 App 모듈로 분류했다.

App에서 사용되는 Config, Router(Navigator), 그리고 Page(Screen)이 들어간다. 이전에 작성했던 Client-Side Clean Architecture에서도 언급했지만, 나는 Page와 View를 구분한다. 그리고 Page구성이 플랫폼 별로 다를 수 있어서 App에 두었다.

Common

프로젝트에서 공통으로 사용되는 기능을 담당한다. 보통 Utility, Helper(validator, parser), constants와 같이 다른 모듈이나 라이브러리에서 자주 사용하는 공통적인 요소를 담당한다.

Shared Models나 State Management 같은 것도 Common에서 다룰 수 있다. 개발자의 성향이나 프로젝트에 따라 별도 패키지로 분리해도 된다.

만약 shared_models나 state_management를 common 패키지에서 따로 분리하여 별도 패키지로 관리한다면,이유는 다음과 같다.

멀티패키지 아키텍처에서는 각 패키지가 독립적으로 개발, 유지보수, 배포될 수 있어야 한다. 공통 model이나 상태관리코드를 common 패키지에 넣으면 해당 패키지가 다른 모든 패키지에 의존성을 가지게 된다. 분리된 패키지를 사용하면 각 패키지가 필요한 모델을 선택적으로 가져와 사용할 수 있으며, 패키지 간의 종속성을 최소화할 수 있다.

Core

앱에서 전체적으로 사용되지만, 핵심이되는 부분들이다. 다른 모듈이나 라이브러리가 이를 참조하여 사용할 수 있도록 인터페이스를 제공한다. 보통 보안, 인증, 인프라 관리 등과 같이 프로젝트의 중요한 부분을 담당한다.

나는 인증 서비스와 같은 서비스, exception이나 error 처리를 위한 규칙 및 로직, Connectivity Health Check나 Http 통신을 위한 Http Client와 같은 것들을 담았다.

core와 common 패키지는 프로젝트에서 공통으로 사용된다는 점에서 비슷해 보이지만 다르다. common과 core의 구분이 어렵다면, 기능을 제공하느냐, 사용되느냐를 개념적으로 구분하면 편하다. 왜냐하면 주체가 되어서 기능을 제공한다는 것이 핵심 기능이라는 근거가 될수 있기 때문이다.

Design System

Theme, Components, Typography 같은 디자인 시스템에 해당하는 것들이 있는 패키지다.

Feature

Feature 패키지는 앱의 특정 기능을 구현하는 모듈들을 담고 있으며, 특정 기능을 완전히 독립적인 단위로 구성하여 개발 가능하다. 각각의 Feature 패키지는 다시 독립적인 하위 패키지들로 구성될 수 있다.

Feature를 설계할 때 참 고민이 많았다. 전에 설계했던 클라이언트-사이드 클린 아키텍처를 그대로 넣을 것인지, 아니면 새로 설계할 것인지 고민했다.

일반적으로 멀티패키지 아키텍처에서의 Feature는 클린 아키텍처와 유사한 방식을 취한다. 각 패키지는 최소한의 의존성을 가지며, 외부로 노출되는 인터페이스를 통해 다른 패키지와 소통한다. 이러한 패키지 간의 인터페이스를 정의함으로써 각 패키지는 독립적으로 개발, 배포, 유지보수할 수 있으며, 전체 시스템의 복잡도를 낮출 수 있다.

따라서, 멀티패키지 아키텍처에서는 Feature가 다른 패키지와 강하게 결합되는 것을 피한다. 이를 통해 각 패키지는 서로 다른 비지니스 기능에 대한 Feature를 구현하면서 모듈성과 확장성을 유지할 수 있다.

그렇기 때문에 일반적으로 데이터와 도메인 로직이 한 패키지 안에 있는 것이 더 좋다. 각 Feature가 자체 데이터를 갖고 필요한 모든 비지니스 로직을 캡슐화 할 수 있으며, 각 Feature가 독립적으로 변경 및 확장될 수 있기 때문이다.

하지만, 멀티 모듈 아키텍처에서는 Feature를 별도의 모듈로 더 작게 분리할 수 있으며, 특히 팀별로 기능을 맡아서 개발하는 분산된 팀 구조에서는 Feature를 여러 모듈로 쪼개는 게 더 유리할 수 있다.

Feature 패키지의 상세 내용에 대해서는 지난 번에 작성했던 Client-Side Clean Architecture로 대신한다.

Sample Project

오늘 작성한 내용에 대한 예시 프로젝트를 만들어놨다.

여기서 받아볼 수 있으며, 자유롭게 포킹해도 된다.(가져갈 때 깃허브 스타가 눌려있다면 성취감이 생길 것 같아요!)

마무리

Software architecture is the art of drawing lines that I call boundaries.
Robert C. Martin, Clean Architecture

SW 설계는 선을 긋는 예술이라는 로버트 마틴의 말 처럼, 경계를 어떻게 나눌 것인가에 대해 고민을 많이했다.

나의 고민이 소프트웨어 설계를 하는 모든 사람들에게 도움이 되었길 바란다.

multi-package architecture하면 monorepo가 빠질 수 없다. Flutter로 git 기반의 monorepo를 구현하는 것에 관심 있으면 Flutter Monorepo를 보길 추천한다.

--

--

Doohyeon Kim
Doohyeon.kim

Developer, SW Engineer, Product Manager. Expert for startup company.