learn-flutter/content/docs/part1/project-structure.md
ChangJoo Park(박창주) 900b0ab68b update markdown
2025-05-14 09:34:13 +09:00

408 lines
11 KiB
Markdown

# Flutter 프로젝트 구조 이해
Flutter 프로젝트는 여러 디렉토리와 파일로 구성되어 있으며, 각각은 프로젝트의 특정 측면을 담당합니다. 이 구조를 이해하면 Flutter 앱을 더 효율적으로 개발하고 관리할 수 있습니다.
## Flutter 프로젝트의 기본 구조
기본적인 Flutter 프로젝트 구조는 다음과 같습니다:
```
my_flutter_app/
├── .dart_tool/
├── .idea/
├── android/
├── build/
├── ios/
├── lib/
├── linux/
├── macos/
├── test/
├── web/
├── windows/
├── .gitignore
├── .metadata
├── analysis_options.yaml
├── pubspec.lock
├── pubspec.yaml
└── README.md
```
이제 각 디렉토리와 파일의 역할을 자세히 살펴보겠습니다.
## 주요 디렉토리
### lib/ 디렉토리
`lib/` 디렉토리는 Flutter 프로젝트의 핵심으로, 앱의 Dart 소스 코드가 저장되는 위치입니다.
```
lib/
├── main.dart # 앱의 진입점
├── models/ # 데이터 모델
├── screens/ # 화면 UI
├── widgets/ # 재사용 가능한 위젯
├── services/ # 비즈니스 로직, API 호출 등
└── utils/ # 유틸리티 기능
```
**중요: 기본적으로 생성되는 것은 `main.dart` 파일뿐이며, 나머지 폴더 구조는 개발자가 필요에 따라 생성하고 구성합니다.**
#### main.dart
`main.dart` 파일은 앱의 진입점으로, `main()` 함수와 루트 위젯을 포함합니다:
```dart
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
```
### test/ 디렉토리
`test/` 디렉토리는 앱의 자동화된 테스트 코드를 포함합니다. 단위 테스트, 위젯 테스트 등을 이 디렉토리에 작성합니다.
```
test/
├── widget_test.dart # 위젯 테스트
└── unit/
└── models_test.dart # 단위 테스트
```
기본적으로 생성되는 `widget_test.dart` 파일은 앱의 메인 위젯을 테스트하는 간단한 예제를 포함합니다:
```dart
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:my_flutter_app/main.dart';
void main() {
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
await tester.pumpWidget(const MyApp());
expect(find.text('0'), findsOneWidget);
expect(find.text('1'), findsNothing);
await tester.tap(find.byIcon(Icons.add));
await tester.pump();
expect(find.text('0'), findsNothing);
expect(find.text('1'), findsOneWidget);
});
}
```
### android/ 디렉토리
`android/` 디렉토리는 Android 플랫폼 관련 코드와 설정을 포함합니다.
```
android/
├── app/
│ ├── src/
│ │ ├── main/
│ │ │ ├── AndroidManifest.xml # 앱 선언 및 권한
│ │ │ ├── kotlin/ # Kotlin 소스 코드
│ │ │ └── res/ # 리소스 (아이콘, 문자열 등)
│ │ └── profile/
│ ├── build.gradle # 앱 수준 빌드 설정
│ └── ...
├── build.gradle # 프로젝트 수준 빌드 설정
├── gradle/
├── gradle.properties
└── ...
```
특히 중요한 파일들:
- **AndroidManifest.xml**: 앱의 이름, 아이콘, 필요한 권한 등을 정의합니다.
- **build.gradle**: 앱의 버전, 의존성, 빌드 설정 등을 구성합니다.
### ios/ 디렉토리
`ios/` 디렉토리는 iOS 플랫폼 관련 코드와 설정을 포함합니다.
```
ios/
├── Runner/
│ ├── AppDelegate.swift # iOS 앱 진입점
│ ├── Info.plist # 앱 구성 및 권한
│ ├── Assets.xcassets/ # 이미지 에셋
│ └── ...
├── Runner.xcodeproj/ # Xcode 프로젝트 파일
└── ...
```
특히 중요한 파일들:
- **Info.plist**: 앱 이름, 버전, 권한 등의 메타데이터를 포함합니다.
- **AppDelegate.swift**: iOS 앱의 진입점 및 초기화 로직을 포함합니다.
### web/, macos/, linux/, windows/ 디렉토리
이 디렉토리들은 각각 웹, macOS, 리눅스, 윈도우 플랫폼을 위한 코드와 설정을 포함합니다. 구조는 플랫폼마다 다르지만, 모두 해당 플랫폼의 네이티브 코드와 구성을 담고 있습니다.
## 주요 설정 파일
### pubspec.yaml
`pubspec.yaml`은 Flutter 프로젝트의 핵심 설정 파일로, 앱의 메타데이터, 의존성, 에셋 등을 정의합니다:
```yaml
name: my_flutter_app
description: A new Flutter project.
# The following defines the version and build number for your application.
version: 1.0.0+1
environment:
sdk: ">=3.0.0 <4.0.0"
# Dependencies
dependencies:
flutter:
sdk: flutter
http: ^1.0.0
shared_preferences: ^2.1.1
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^2.0.0
# Flutter-specific configurations
flutter:
uses-material-design: true
# Assets
assets:
- assets/images/
- assets/fonts/
# Fonts
fonts:
- family: Roboto
fonts:
- asset: assets/fonts/Roboto-Regular.ttf
- asset: assets/fonts/Roboto-Bold.ttf
weight: 700
```
주요 항목들:
- **name**: 앱의 패키지 이름
- **version**: 앱의 버전(`버전 코드+빌드 번호` 형식)
- **dependencies**: 앱이 사용하는 패키지 의존성
- **dev_dependencies**: 개발 시에만 필요한 패키지 의존성
- **flutter**: Flutter 특화 설정 (에셋, 폰트, 테마 등)
### analysis_options.yaml
`analysis_options.yaml`은 Dart 코드 분석기의 설정을 정의하여 코드 품질과 일관성을 유지하는 데 도움을 줍니다:
```yaml
include: package:flutter_lints/flutter.yaml
linter:
rules:
- avoid_print
- avoid_empty_else
- prefer_const_constructors
- sort_child_properties_last
analyzer:
errors:
missing_required_param: error
missing_return: error
```
### .gitignore
`.gitignore` 파일은 Git 버전 관리 시스템에서 무시해야 할 파일들을 지정합니다. Flutter 프로젝트에서는 빌드 결과물, 임시 파일, IDE 파일 등이 여기에 포함됩니다.
## 추가 디렉토리와 파일 (선택적)
개발자들은 프로젝트의 규모와 복잡성에 따라 추가 디렉토리를 생성할 수 있습니다:
### assets/ 디렉토리
```
assets/
├── images/ # 이미지 파일
├── fonts/ # 폰트 파일
└── data/ # JSON, CSV 등의 데이터 파일
```
이 디렉토리는 `pubspec.yaml`에 명시적으로 등록해야 합니다:
```yaml
flutter:
assets:
- assets/images/
- assets/fonts/
- assets/data/
```
### l10n/ 또는 i18n/ 디렉토리
다국어 지원을 위한 디렉토리:
```
l10n/
├── app_en.arb # 영어 번역
├── app_ko.arb # 한국어 번역
└── app_ja.arb # 일본어 번역
```
## 프로젝트 구조화 패턴
Flutter 앱의 구조는 프로젝트의 성격과 팀의 선호도에 따라 달라질 수 있습니다. 일반적으로 많이 사용되는 패턴은 다음과 같습니다:
### 기능별 구조 (Feature-First)
앱의 기능별로 디렉토리를 구성하는 방식:
```
lib/
├── main.dart
├── features/
│ ├── auth/
│ │ ├── screens/
│ │ ├── widgets/
│ │ ├── models/
│ │ └── services/
│ ├── home/
│ ├── profile/
│ └── settings/
└── shared/
├── widgets/
├── utils/
└── constants/
```
이 구조는 기능이 많은 대규모 앱에 적합합니다.
### 계층별 구조 (Layer-First)
앱의 아키텍처 계층별로 디렉토리를 구성하는 방식:
```
lib/
├── main.dart
├── screens/ # 모든 화면 UI
├── widgets/ # 모든 재사용 위젯
├── models/ # 모든 데이터 모델
├── services/ # 모든 서비스 로직
├── repositories/ # 데이터 액세스 로직
└── utils/ # 유틸리티 함수
```
이 구조는 작거나 중간 규모의 앱에 적합합니다.
### MVVM 또는 Clean Architecture
보다 체계적인 아키텍처 패턴을 적용한 구조:
```
lib/
├── main.dart
├── ui/
│ ├── screens/
│ └── widgets/
├── viewmodels/
├── models/
├── services/
├── repositories/
└── core/
├── utils/
└── constants/
```
이 구조는 코드의 유지 관리성과 테스트 가능성을 높이는 데 도움이 됩니다.
## 모범 사례 및 권장 사항
### 1. 명확한 명명 규칙
- 파일 이름: `snake_case.dart` (예: `user_profile.dart`)
- 클래스 이름: `PascalCase` (예: `UserProfile`)
- 변수 및 함수 이름: `camelCase` (예: `userName`, `getUserInfo()`)
### 2. 프로젝트 구조 일관성 유지
- 처음부터 명확한 구조 계획 수립
- 프로젝트 전체에 동일한 규칙 적용
- 팀 내 구조 합의 및 문서화
### 3. 관련 코드 그룹화
- 관련된 코드는 함께 위치
- 너무 깊은 중첩 디렉토리 피하기 (일반적으로 3-4 수준 이내)
- 디렉토리 이름은 내용을 명확히 반영
### 4. 불필요한 분할 피하기
- 파일이 너무 많아지면 관리가 어려울 수 있음
- 단일 위젯이나 작은 기능을 여러 파일로 나누지 않기
- 너무 큰 파일도 피하기 (일반적으로 300-500줄 이내)
## 기타 고려 사항
### 환경 구성
다양한 환경(개발, 스테이징, 프로덕션)에 대한 구성을 지원하기 위해 다음과 같은 접근 방식을 사용할 수 있습니다:
```
lib/
├── main.dart # 공통 진입점
├── main_dev.dart # 개발 환경 진입점
├── main_staging.dart # 스테이징 환경 진입점
├── main_prod.dart # 프로덕션 환경 진입점
└── config/
├── app_config.dart # 환경 설정 클래스
├── dev_config.dart
├── staging_config.dart
└── prod_config.dart
```
### 라우팅 구성
앱의 화면 전환을 관리하기 위한 라우팅 구성:
```
lib/
├── router/
│ ├── app_router.dart # 라우터 설정
│ └── routes.dart # 라우트 상수
```
### 상태 관리
선택한 상태 관리 솔루션에 따라 구조가 달라질 수 있습니다:
```
lib/
├── providers/ # Riverpod/Provider
├── blocs/ # Flutter_bloc
├── stores/ # MobX
└── state/ # 기타 상태 관리
```
## 결론
Flutter 프로젝트 구조는 규모와 복잡성에 따라 다양하게 적용할 수 있습니다. 중요한 것은 팀이 이해하기 쉽고 유지 관리가 용이한 일관된 구조를 선택하는 것입니다. 프로젝트가 성장함에 따라 구조도 진화할 수 있으므로, 리팩토링과 개선에 열린 자세를 유지하는 것이 좋습니다.
이제 Flutter 개발 환경 설정과 프로젝트 구조에 대한 이해를 바탕으로, 다음 챕터에서 Dart 언어 기초를 배워보겠습니다.