Skip to main content

Command Palette

Search for a command to run...

[Flutter] Flutter Project Structure : Feature-first vs Layer-first

Updated
3 min read

Flutter에서 단일 페이지 앱을 만들 때에는 하나의 폴더에 모든 파일들을 넣어도 된다. 하지만 다양한 페이지와 데이터 모델들을 추가하기 시작할 때, 파일들을 어떻게 일관적인 방식으로 정리할 수 있을까?

대표적인 방식으로 feature-first 구조와 layer-first 구조가 있다.

Layer-first (feature inside layers)

‣ lib 
    ‣ src 
        ‣ presentation 
            ‣ feature1 
            ‣ feature2 
        ‣ application 
            ‣ feature1 
            ‣ feature2 
        ‣ domain 
            ‣ feature1 
            ‣ feature2 
        ‣ data 
            ‣ feature1 
            ‣ feature2

feature inside layers

각각의 layer마다 Dart 파일을 넣는 대신, 폴더를 생성한다. 서로 관련 있는 Dart 파일들을 각각의 feature 폴더에 추가한다. (widgets, controllers는 presentation 폴더 안에, models는 domain 안에)

만약 feature3를 추가하고 싶다면, 각각의 layer마다 feature3 폴더를 넣는다:

‣ lib 
    ‣ src 
        ‣ presentation
            ‣ feature1 
            ‣ feature2 
            ‣ feature3 <--
        ‣ application 
            ‣ feature1 
            ‣ feature2 
            ‣ feature3 <--
        ‣ domain 
            ‣ feature1 
            ‣ feature2 
            ‣ feature3 <--
        ‣ data 
            ‣ feature1 
            ‣ feature2 
            ‣ feature3 <--

Layer-first 구조의 단점

하나의 feature에 대해 다른 layer에 속한 파일들은 서로 멀리 떨어져 있다. 따라서 프로젝트의 여러 곳을 계속해서 이동해야 하기 때문에, 각각의 feature에 대해 작업하기 번거롭다. 또한 특정 feature을 삭제하려고 할 때, 일부 파일을 까먹을 수 있다. 각 파일들이 layer에 의해 정렬되어 있기 때문이다. 이러한 이유 때문에, 대규모의 앱을 만들 때에는 이어서 설명할 feature-first 구조를 선택하는 것이 좋다.

Feature-first (layers inside features)

feature-first 구조에서는 모든 새로운 feature마다 새로운 폴더를 생성한다. 그리고 해당 폴더 안에 layer을 집어넣는다.

‣ lib 
    ‣ src 
        ‣ features 
            ‣ feature1 
                ‣ presentation 
                ‣ application 
                ‣ domain 
                ‣ data 
            ‣ feature2 
                ‣ presentation 
                ‣ application 
                ‣ domain 
                ‣ data

이러한 구조가 더 논리적이다. 특정 feature에 해당하는 파일들이 layer로 그룹화되어 쉽게 찾을 수 있기 때문이다.

layer-first 구조보다 좋은 점

  • 새로운 feature을 추가하거나 수정하고 싶을 때, 하나의 폴더에서만 작업을 하면 된다.

  • 특정 feature을 삭제하려면, 하나의 폴더만 삭제하면 된다.

Common mistakes

Feature-first 는 UI에 관한 구조가 아니다!!

feature을 단순히 앱 스크린 상의 페이지로 생각할 수도 있다.

예를 들면:

‣ lib 
    ‣ src 
        ‣ features 
            ‣ account 
            ‣ admin 
            ‣ checkout 
            ‣ leave_review_page 
            ‣ orders_list 
            ‣ product_page 
            ‣ products_list 
            ‣ shopping_cart 
            ‣ sign_in

위 코드에서 각각의 feature은 앱의 실제 화면에 따라 분류되어 있다. 이처럼 UI에 의한 feature-first 구조로 접근하면 안 된다.

Feature란 무엇인가?

💡
유저가 '보는' 게 아닌 '하는' 것 (장바구니 담기, 주문 조회하기, 리뷰 남기기 등)

How to do feature-first, the right way

  • domain layer부터 시작해서 model classes와 이 classes를 관리하기 위한 business logic을 찾아내라

  • 각각의 모델에 대한 폴더를 생성한다

  • 폴더마다 'presentation','application','domain','data' 같은 sub 폴더를 생성한다.

  • 해당 sub 폴더에 필요한 파일을 넣는다

결론

feature-first 구조가 layer-first에 비해 많은 장점을 가진다. domain 주도 설계를 적용한다면, 앱 내의 서로 다른 layers와 components 간에 명확한 경계가 형성될 것이다. 이로써 후에 의존성 문제를 효율적으로 관리할 수 있게 된다.

D

김성중 Feature-first를 적용하는 경우에서 만약 다양한 feature에서 공통적으로 사용되는 위젯이 있다면 이건 어떤 방식으로 처리하는 게 좋을까요?

More from this blog

[ZSH] tree 사용하기

들어가며 큰 규모의 프로젝트를 출시한 뒤, 후일을 위해서 더 늦기 전에 파일 정리 및 문서화를 진행해야했다. 문서화 작업을 하는 중에 기왕 정리하는 거 파일 구조를 이쁘게 트리 구조로 나열하여 코멘트를 달면 나중에 보더라도 이해하기 더 쉬울 것 같았다. 어떻게 해야 간지나는 트리 구조를 만들 수 있을까 방법을 찾다보니 역시나 파일 구조를 트리로 이쁘게 출력해주는 커맨드 툴이 존재했다. tree 커맨드에 대해서 알아보고 알짜배기 내용만 정리했다....

Feb 21, 20242 min read

[Next.js] parallel routes & intercepting routes

트위터 로그인 모달창을 만들어보며 넥스트의 parallel routes 와 intercepting routes 을 학습한 내용을 정리해보았습니다. 트위터 로그인 창을 확인해봅시다. 루트 디렉토리 화면을 배경으로 i/flow/login 페이지가 동시에 표시되고 있습니다. 저는 app router 를 학습하기 전까지는 createPortal 을 사용하여 포탈 영역에 로그인 컴포넌트를 띄우는 방식을 사용했었습니다. const NoLogin =()=...

Feb 1, 20244 min read

C/C++ 이진 트리(binary tree) 개요 및 구현(1)

개요 트리는 노드들이 나무 가지처럼 연결된 비선형 계층적 자료구조이다. 하위 트리가 존재하고, 그 노드에 또 하위 트리가 존재하는 자료구조 이다. 트리의 맨 위에 있는 루트 노드가 존재한다. 우리가 알아볼 트리는 이진 트리이다. 이진 트리는 자식 노드(부모로부터 아래로 이어진 노드)가 2개 이하인 구조를 말한다. 트리의 사용 사례로는 다음과 같다 계층 적 데이터 저장(파일,폴더) 효율적인 검색 속도 힙 데이터 베이스의 인덱싱 트리에 ...

Jan 31, 20244 min read

[React] Server component (RSC)

React.js 18 에 도입된 리액트 서버 컴포넌트는 서버에서 동작하는 리액트 컴포넌트를 의미합니다. Next가 권장하는 라우팅 방식인 app router의 기반이 되는 컴포넌트이기 때문에 app router 를 이해하기 위해서는 server component 에 대한 이해가 필요합니다. server component 리액트는 클라이언트단만을 컴포넌트화하는 대신, server component라는 개념을 통해 서버 영역을 컴포넌트화합니다. ...

Jan 29, 20243 min read

Flutter, JavaScript

42 posts