print("비난, 조롱 없이 내 팀과 선수를 응원하는 커뮤니티")
print("와블 iOS 레포지토리입니다 🚀")
Prefix | 설명 |
---|---|
Feat |
기능 구현 |
Add |
파일(이미지, 폰트 등 포함) 추가 |
Delete |
파일 삭제 |
Chore |
이외 자잘한 수정 |
Refactor |
코드의 비즈니스 로직 수정 |
Fix |
버그 등의 기능 전체 수정 |
Style |
UI 스타일(오토레이아웃 등) 설정 |
Setting |
프로젝트 설정 |
Docs |
문서 작성 |
[Prefix] #이슈번호 - 메세지 내용
[Feat] #1 - 로그인 기능 구현
Library | Description |
---|---|
Moya | 추상화된 네트워크 레이어를 보다 간편하게 사용하기 위함 |
CombineMoya | Combine을 활용한 네트워크 요청을 보다 효율적으로 처리하기 위함 |
Then | UI 구현 시, 클로저를 통해 인스턴스를 보다 간편하게 초기화하기 위함 |
Snapkit | UI 구현에서 오토레이아웃을 간편하게 적용하기 위함 |
Lottie | JSON 기반 애니메이션을 UI에 쉽게 적용하기 위함 |
Kingfisher | 이미지 캐싱 및 다운로드 최적화를 통해 UI 성능을 개선하기 위함 |
KakaoOpenSDK | 카카오 소셜 로그인 및 API 활용을 위함 |
Firebase | FCM을 이용한 푸시 알림 및 백엔드 기능 활용을 위함 |
Amplitude-Swift | 사용자 행동 분석을 위한 이벤트 트래킹을 위함 |
📁 Wable-iOS
├── 📁 App
│ ├── AppDelegate
│ ├── SceneDelegate
├── 📁 Resource
│ ├── 📁 Config
│ ├── 📁 Font
│ ├── 📁 Animation
│ ├── 📁 Info
│ ├── 📁 Assets
│ │ ├── 📁 Color
│ ├── LaunchScreen
│ ├── ViewController
├── 📁 Core
│ ├── 📁 DI
│ ├── 📁 Combine+
│ ├── 📁 Logger
├── 📁 Infra
│ ├── 📁 Token
│ ├── 📁 Keychain
│ ├── 📁 Network
│ │ ├── 📁 OAuth
│ │ ├── APIProvider
│ │ ├── NetworkError
│ │ ├── MoyaLoggingPlugin
│ │ ├── 📁 Bundle
│ │ ├── 📁 TargetType
│ │ ├── 📁 DTO
├── 📁 Data
│ ├── 📁 RepositoryImpl
│ ├── 📁 Mapper
├── 📁 Domain
│ ├── 📁 Error
│ ├── 📁 RepositoryInterface
│ ├── 📁 Entity
- 한 줄 당 최대 글자 수는 120자로 제한한다.
- 들여쓰기 제한은 최대 5번까지만 허용한다. 6번 이상 들여쓰기가 필요할 경우 메서드 분리로 최대한 가독성을 지켜 작성한다.
- **자동 포매팅(
Control
+M
)**을 적극적으로 활용한다.
퍼스트 파티와 서드 파티를 구분하여 각각 알파벳 순으로 정렬한다. 퍼스트 파티를 먼저 작성한다.
import Combine
import Foundation
import CombineMoya
import Moya
- 프로토콜: 구현하고자 하는 객체 이름으로 네이밍한다.
- 실구현체: 프로토콜 이름 +
Impl
접미사 형태로 네이밍한다.
protocol UserRepository {}
final class UserRepositoryImpl: UserRepository {}
메서드의 역할에 따라 일관된 접두사를 사용한다.
- 조회:
fetch
- 수정:
update
- 삭제:
delete
- 생성:
create
- 초기 상태 설정:
configure
- 액션 메서드:
~DidTap
형식
Setup
관련 메서드는 다음 명명 규칙과 역할에 따라 구분하여 작성한다.
아래 순서대로 차례대로 작성한다.
메서드명 | 역할 및 담당 업무 |
---|---|
setupNavigationBar() |
네비게이션 바 설정 및 구성 |
setupView() |
해당 클래스의 프로퍼티 관리, 기본 뷰 설정 |
setupConstraints() |
addSubviews, SnapKit 등 오토레이아웃 관련 코드 |
setupAction() |
액션 이벤트 관련 설정 |
setupDelegate() |
Delegate, DataSource 관련 코드 |
setupDataSource() |
데이터 소스 초기화 및 설정 |
setupBinding() |
데이터 바인딩 및 리액티브 프로그래밍 관련 코드 |
MARK 주석은 위아래로 한 줄씩 공백을 두고 작성하며, 되도록이면 아래 순서를 준수한다.
// MARK: - Section & Item
// MARK: - Typealias
// MARK: - Property
// MARK: - UIComponent
// MARK: - Life Cycle
Extension은 public으로 선언하고 내부에서 필요한 부분만 private으로 선언한다. 되도록이면 아래 순서를 준수한다.
// MARK: - Delegate 관련 Extension들
// MARK: - Computed Property
// MARK: - Setup Method
// MARK: - Helper Method (재사용성을 위한 private 메서드)
// MARK: - Action Method (@objc 메서드)
// MARK: - UICollectionViewCompositionalLayout (CollectionView 레이아웃 관련 코드)
// MARK: - Constant
120자를 초과하는 경우 다음과 같이 개행한다.
let result = someCondition
? valueWhenTrue
: valueWhenFalse
반드시 아래와 같은 양식으로 개행해 작성한다.
if condition {
// 실행 코드
} else {
// 실행 코드
}
120자 이하인 경우 한 줄로 작성 가능하며, 초과 시 개행한다.
// 120자 이하인 경우
guard let self = self, let profile = sessionProfile else { return }
// 120자 초과인 경우
guard let self = self,
let profile = sessionProfile,
let userData = profile.userData
else {
return
}
한 줄로 작성 가능하고 120자 이하인 경우 개행하지 않는다.
// 한 줄 작성 가능
items.map { $0.name }
// 복잡하거나 120자보다 긴 경우 개행
items.compactMap { item in
return item.isValid ? item.processedValue : nil
}
다음 조건에 해당하는 경우 lazy var
를 사용한다.
- 호출되지 않을 가능성이 있는 프로퍼티
- 용량이 큰 리소스 (특히 애셋 파일이나 화면을 꽉 채우는 이미지)
private lazy var backgroundImageView: UIImageView = {
let imageView = UIImageView()
imageView.image = UIImage(named: "large-background-image")
return imageView
}()
DTO
에서 Entity로
변환하는 Mapper는
다음 규칙을 따른다.
enum
의static
메서드로 구현- 메서드명:
map(with dto:)
enum UserMapper {
static func map(with dto: UserDTO) -> User {
return User(
id: dto.id,
name: dto.name,
email: dto.email
)
}
}
객체에서 반복되는 숫자나 문자열은 중첩 타입으로 Constant
를 정의하여 관리한다.
final class CustomView: UIView {
// 구현 코드
}
// MARK: - Constant
private extension CustomView {
enum Constant {
static let padding: CGFloat = 16
static let cornerRadius: CGFloat = 8
static let animationDuration: TimeInterval = 0.3
}
}
성능 테스트와 관련된 지침은 추후 업데이트 예정이며 현재는 다음 기본 원칙을 준수한다.
- 메모리 누수 방지를 위한 적절한
weak
참조 사용 - 불필요한 연산 최소화
- 적절한 캐싱 전략 적용