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

·

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 간에 명확한 경계가 형성될 것이다. 이로써 후에 의존성 문제를 효율적으로 관리할 수 있게 된다.