-
Notifications
You must be signed in to change notification settings - Fork 0
Convention
해당 문서는 DayTodo Android 파트에서 사용하는 컨벤션 및 Git 전략을 정리한 문서입니다.
본 프로젝트는 Jetpack Compose 프로젝트이며, MVVM 패턴과 멀티모듈 아키텍처를 기반으로 개발합니다.
본 프로젝트는 Git Flow 전략을 기반으로 브랜치를 관리합니다.
| 브랜치 | 설명 |
|---|---|
main |
실제 배포에 사용되는 브랜치 |
develop |
개발 중인 기능이 합쳐지는 기준 브랜치 |
release/* |
배포 전 테스트 및 안정화를 위한 브랜치 |
feature/* |
새로운 기능 개발을 위한 브랜치 |
fix/* |
버그 수정을 위한 브랜치 |
hotfix/* |
운영 환경에서 발생한 긴급 오류 수정을 위한 브랜치 |
- 새로운 기능 개발은
develop브랜치를 기준으로feature/*브랜치를 생성합니다. - 개발 중 발생한 버그 수정은
develop브랜치를 기준으로fix/*브랜치를 생성합니다. - 배포 테스트 중 발생한 버그 수정은
release/*브랜치를 기준으로fix/*브랜치를 생성합니다. - 운영 환경에서 긴급 오류가 발생한 경우
main브랜치를 기준으로hotfix/*브랜치를 생성합니다.
| 상황 | 병합 방향 |
|---|---|
| 기능 개발 완료 |
feature/* → develop
|
| 개발 중 버그 수정 완료 |
fix/* → develop
|
| 배포 테스트 중 버그 수정 완료 |
fix/* → release/*
|
| 배포 테스트 시작 |
develop → release/*
|
| 실제 배포 반영 |
release/* → main
|
| 배포 안정화 내용 반영 |
release/* → develop
|
| 운영 긴급 수정 반영 |
hotfix/* → main, develop
|
브랜치명은 작업 목적과 내용을 명확히 알 수 있도록 작성합니다.
브랜치종류/이슈번호-작업내용
- 브랜치명은 영어 소문자로 작성합니다.
- 단어 사이는 하이픈으로 구분합니다.
- 브랜치 종류는 작업 목적에 맞게 사용합니다.
- 이슈 번호가 있는 경우 브랜치명에 포함합니다.
- 작업 내용은 간결하되 의미가 드러나도록 작성합니다.
| 종류 | 사용 목적 |
|---|---|
feature |
새로운 기능 개발 |
fix |
버그 수정 |
release |
배포 전 테스트 및 안정화 |
hotfix |
운영 환경 긴급 수정 |
chore |
설정, 빌드, 의존성 등 기타 작업 |
커밋 메시지는 작업 내용을 명확히 표현하도록 작성합니다.
헤더: 커밋 메시지 내용
| 헤더 | 의미 |
|---|---|
feat |
새로운 기능 추가 |
fix |
버그 수정 |
refactor |
기능 변화 없는 코드 개선 |
docs |
문서 작성 및 수정 |
chore |
설정, 빌드, 의존성 등 기타 작업 |
test |
테스트 코드 작성 및 수정 |
- 커밋 메시지는 한글로 작성합니다.
- 하나의 커밋에는 하나의 작업 단위만 포함합니다.
- 작업 내용을 구체적으로 작성합니다.
- 의미가 모호한 표현은 사용하지 않습니다.
- 커밋 헤더와 실제 작업 내용이 일치해야 합니다.
모든 작업은 Pull Request를 통해 병합합니다.
- 작업이 완료된 후 PR을 생성합니다.
- PR을 생성하기 전 기준 브랜치의 최신 내용을 반영합니다.
- PR을 생성하기 전 앱 실행 및 주요 기능 동작을 확인합니다.
- 하나의 PR에는 하나의 작업 단위만 포함하는 것을 원칙으로 합니다.
PR 제목은 커밋 메시지 형식과 동일하게 작성합니다.
헤더: 작업 내용
PR 본문에는 다음 내용을 포함합니다.
## 작업 내용
## 실행 결과
## 리뷰어 참고 사항- PR 작성자는 최소 1명 이상의 팀원을 리뷰어로 지정합니다.
- 작업한 기능과 관련 있는 팀원을 우선적으로 리뷰어로 지정합니다.
- 공통 모듈, 핵심 구조, 아키텍처, 배포 관련 변경은 팀원 전체가 확인할 수 있도록 공유합니다.
다음 조건을 만족한 경우에만 PR을 머지합니다.
- 최소 1명 이상의 리뷰 승인을 받았는가
- 충돌이 없는가
- 앱 빌드가 정상적으로 완료되는가
- 주요 기능 동작을 직접 확인했는가
- PR 내용과 실제 변경 사항이 일치하는가
- 불필요한 주석, 로그, 테스트 코드가 제거되었는가
- 코드 네이밍 및 패키지 구조 규칙을 준수했는가
- 공통 모듈 변경 시 영향 범위를 확인했는가
- 머지 완료 후 작업 브랜치는 삭제합니다.
-
main,develop브랜치에는 직접 push하지 않습니다. - 배포 관련 브랜치 병합 시에는 팀원과 사전에 공유합니다.
- 이름만 보고 역할을 알 수 있도록 작성합니다.
- 축약어 사용은 최소화합니다.
- 의미가 모호한 이름은 사용하지 않습니다.
- 같은 개념은 프로젝트 전체에서 동일한 이름으로 사용합니다.
| 대상 | 규칙 |
|---|---|
| Class | PascalCase |
| Interface | PascalCase |
| Object | PascalCase |
| Enum Class | PascalCase |
| Data Class | PascalCase |
| Sealed Class | PascalCase |
| 대상 | 규칙 |
|---|---|
| 변수 | camelCase |
| 함수 | camelCase |
| 파라미터 | camelCase |
| 지역 변수 | camelCase |
| Boolean 변수 |
is, has, can, should 등으로 시작 |
| 대상 | 규칙 |
|---|---|
| 상수 | UPPER_SNAKE_CASE |
| 특정 Key | UPPER_SNAKE_CASE |
| 대상 | 접미사 |
|---|---|
| Activity | Activity |
| Fragment | Fragment |
| ViewModel | ViewModel |
| Adapter | Adapter |
| ViewHolder | ViewHolder |
| Dialog | Dialog |
| BottomSheet | BottomSheet |
| Service | Service |
| Receiver | Receiver |
리소스명은 소문자와 언더스코어를 사용합니다.
| 리소스 | 규칙 |
|---|---|
| Layout | 화면_역할 |
| Drawable | 종류_이름_상태 |
| Icon | ic_이름 |
| Image | img_이름 |
| Color | 의미 중심 이름 |
| String | 화면 또는 기능 기준 이름 |
| Style | 역할 중심 이름 |
View는 Activity, Compose Screen 등을 의미합니다. 역할은 다음과 같습니다.
- UI 렌더링
- 사용자 이벤트 전달
- ViewModel의 상태 관찰
- 화면 이동 처리
- 권한 요청 및 Android Framework 관련 처리
View에서는 다음 작업을 지양합니다.
- 비즈니스 로직 처리
- 직접적인 데이터 가공
- Repository 직접 호출
- 네트워크 요청 직접 수행
ViewModel은 화면 상태와 사용자 이벤트 처리를 담당합니다. 역할은 다음과 같습니다.
- UI State 관리
- 사용자 이벤트 처리
- UseCase 호출
- 로딩, 성공, 실패 상태 관리
- View에 필요한 데이터 형태로 가공
UseCase는 하나의 비즈니스 동작을 담당합니다. 역할은 다음과 같습니다.
- ViewModel과 Repository 사이의 비즈니스 로직 처리
- 여러 Repository 조합
- 도메인 규칙 처리
- 재사용 가능한 기능 단위 제공
Repository는 데이터 접근을 추상화합니다.
Repository의 인터페이스는 :domain 모듈에 정의하고, 실제 구현체는 :data 모듈에 작성합니다. 역할은 다음과 같습니다.
- API 호출 흐름 관리
- 로컬 데이터 접근 흐름 관리
- 데이터 소스 선택
- DTO와 Domain Model 간 변환
- 에러 처리
- 데이터 캐싱 전략 처리
DTO는 서버 요청 및 응답 데이터를 표현하는 객체입니다.
DTO는 :data 모듈 내부에 위치하며, 서버 통신을 위한 데이터 구조를 담당합니다.
DTO 사용 규칙은 다음과 같습니다.
- DTO는 서버 요청 및 응답 구조를 표현합니다.
- View와 ViewModel에서는 DTO를 직접 사용하지 않고, DTO를 Domain Model로 변환한 뒤 사용합니다.
- DTO와 Domain Model 간 변환 함수는 DTO 파일 내부에 확장 함수 형태로 정의할 수 있습니다.
본 프로젝트는 기능별 책임 분리와 의존성 관리를 위해 멀티모듈 구조를 사용합니다.
Root
├── :app
├── :build-logic
│ └── :convention
├── :core
├── :uikit
├── :data
├── :domain
└── :feature
├── :feature:*
| 모듈 | 역할 |
|---|---|
:app |
앱 진입점, 전체 네비게이션 연결, 의존성 조립 |
:build-logic |
Gradle convention plugin 관리 |
:build-logic:convention |
공통 빌드 설정, 플러그인, 의존성 설정 관리 |
:core |
비UI 공통 코드, 공통 유틸, 확장 함수, Result 래퍼, 네트워크 기반 설정, 로컬 저장소 기반 설정 |
:uikit |
공통 UI 컴포넌트, 디자인 시스템, 테마, 색상, 타이포그래피 |
:data |
API 인터페이스, DTO, Repository 구현체, 데이터 변환 처리 |
:domain |
UseCase, Repository 인터페이스, Domain Model |
:feature:* |
기능별 화면, ViewModel, UI State, UI Event 관리 |
모듈 간 의존성은 아래와 같이 단방향으로 흐르도록 관리합니다.
:feature:* → :domain
:feature:* → :uikit
:feature:* → :core
:data → :domain
:data → :core
:uikit → :core
:app → :feature:*
:app → :data
:app → :domain
:app → :uikit
:app → :core
View
→ ViewModel
→ UseCase
→ Repository Interface
→ Repository Implementation
→ API / Local Storage
app
├── navigation
└── di
| 패키지 | 역할 |
|---|---|
navigation |
앱 전체 네비게이션 연결 |
di |
앱 전체 의존성 주입 설정 |
core
├── common
├── network
└── datastore
| 패키지 | 역할 |
|---|---|
common |
공통 상수, 확장 함수, Result 래퍼, 공통 유틸 |
network |
Retrofit, OkHttp 등 네트워크 기반 설정 |
datastore |
DataStore 기반 로컬 저장소 설정 및 관리 |
uikit
├── designsystem
├── component
├── dialog
└── bottomsheet
| 패키지 | 역할 |
|---|---|
designsystem |
색상, 타이포그래피, 테마 등 디자인 시스템 |
component |
여러 화면에서 재사용되는 공통 UI 컴포넌트 |
dialog |
공통 Dialog 컴포넌트 |
bottomsheet |
공통 BottomSheet 컴포넌트 |
feature
├── navigation
├── screen
├── component
├── state
└── viewmodel
| 패키지 | 역할 |
|---|---|
navigation |
해당 기능의 화면 이동 정의 |
screen |
화면 단위 UI |
component |
해당 기능에서만 사용하는 UI 컴포넌트 |
state |
UI State, UI Event, UI Effect 정의 |
viewmodel |
ViewModel 관리 |
domain
├── model
├── repository
└── usecase
| 패키지 | 역할 |
|---|---|
model |
도메인 모델 |
repository |
Repository 인터페이스 |
usecase |
비즈니스 로직 단위 |
data
├── api
├── dto
└── repository
| 패키지 | 역할 |
|---|---|
api |
Retrofit API 인터페이스 |
dto |
요청 및 응답 DTO, DTO와 Domain Model 간 변환 함수 |
repository |
Repository 구현체 |
- 패키지명은 소문자로 작성합니다.
- 기능과 역할이 불분명한 패키지는 만들지 않습니다.
- 특정 기능에서만 사용하는 코드는 해당
feature모듈 내부에 둡니다. - 여러 기능에서 공통으로 사용하는 UI 코드는
:uikit모듈로 분리합니다. - 여러 기능에서 공통으로 사용하는 비UI 코드는
:core모듈로 분리합니다. - 공통으로 사용될 가능성만으로
:core또는:uikit에 먼저 분리하지 않습니다. - View, ViewModel, UseCase, Repository의 역할을 명확히 분리합니다.
- 순환 의존성이 발생하지 않도록 모듈 간 참조 방향을 유지합니다.