Files
sodalive-ios/docs/agent-guides/code-style.md

4.7 KiB

코드 스타일 가이드

SodaLive iOS 코드 작성 시 따르는 스타일 규칙이다. 기존 코드 관례와 충돌하면 더 가까운 주변 코드의 패턴을 우선한다.

아키텍처/레이어

  • 기본 흐름은 View -> ViewModel -> Repository -> Api(TargetType)를 따른다.
  • 기존 로직 수정이 아닌 신규 View, ViewModel, Repository 및 그와 연결된 하위 코드는 SodaLive/Sources/V2/** 하위에 작성한다.
  • API는 enum ...Api: TargetType, 저장소는 final class ...Repository 형태를 우선 사용한다.
  • 상태 모델은 struct/enum 중심으로 두고, 화면 상태는 ObservableObject에서 관리한다.

컴포넌트 위치 규칙

  • 여러 페이지에서 재사용 가능한 컴포넌트는 SodaLive/Sources/V2/Component/** 아래에 작성한다.
  • 공용 컴포넌트는 기능/페이지 접두사가 아니라 UI 형태나 역할 기준 폴더에 배치한다.
    • 카드 형태: SodaLive/Sources/V2/Component/Card
    • 배너/캐러셀 형태: SodaLive/Sources/V2/Component/Banner
    • 텍스트 표시/확장/축약 형태: SodaLive/Sources/V2/Component/Text
    • 버튼 형태: SodaLive/Sources/V2/Component/Button
    • 크리에이터 프로필/그리드 형태: SodaLive/Sources/V2/Component/Creator
  • 공용 컴포넌트 타입명은 HomeRecommendation..., MainHome...처럼 특정 페이지나 API 이름을 접두사로 붙이지 않는다. 예: CommunityPostCard, BannerCarousel, ExpandableTextView.
  • 공용 컴포넌트는 특정 API 응답 모델에 직접 의존하지 않는 것을 우선한다. 필요한 값은 표시용 프로퍼티 또는 작은 display model로 받는다.
  • 특정 페이지 내부에서만 사용하는 컴포넌트는 해당 페이지 폴더 하위 Components에 둔다. 예: SodaLive/Sources/V2/Main/Home/Components/MainHomeLiveSection.swift.
  • 페이지 전용 컴포넌트는 페이지 문맥을 드러내기 위해 MainHome...처럼 페이지 접두사를 사용할 수 있다.
  • 처음에는 페이지 전용으로 만들었더라도 다른 페이지에서 재사용 요구가 생기면 SodaLive/Sources/V2/Component/**의 적절한 형태별 폴더로 이동한다.
  • 공용으로 만들지 페이지 전용으로 둘지 애매하면, 현재 요청 범위 기준으로만 판단한다. 재사용 근거가 없으면 페이지 전용으로 시작한다.

임포트 규칙

  • 시스템 프레임워크(Foundation, SwiftUI, Combine)를 먼저 배치한다.
  • 서드파티(Moya, CombineMoya, SDK들)는 이후 배치한다.
  • import 그룹 사이에는 한 줄 공백으로 의미 단위를 분리한다.

포맷/구조

  • 들여쓰기는 4칸 스페이스를 사용한다.
  • 프로퍼티 선언, 비즈니스 로직, 헬퍼 메서드는 공백 줄로 구획한다.
  • 클로저 체인은 줄바꿈해 가독성을 유지한다.

타입/상태 관리

  • ViewModel은 final class ...: ObservableObject 패턴을 우선한다.
  • View가 소유하는 객체는 @StateObject, 외부 주입 객체는 @ObservedObject를 사용한다.
  • 네트워크 반환은 AnyPublisher<Response, MoyaError> 패턴을 기본으로 따른다.

네이밍 규칙

  • 타입명은 PascalCase (HomeViewModel, UserRepository, UserApi).
  • 변수/함수는 camelCase (errorMessage, getMemberInfo).
  • 역할을 이름에 반영한다 (*View, *ViewModel, *Repository, *Api, *Request, *Response).

비동기/Combine 규칙

  • 비동기 처리는 Combine의 sink, receiveValue, .store(in: &subscription) 패턴을 따른다.
  • sink 완료 블록에서 .failure를 반드시 처리한다.
  • 클로저 캡처는 상황에 맞게 [weak self] 또는 [unowned self]를 선택한다.

에러 처리 규칙

  • 사용자 노출 오류는 errorMessage와 팝업 플래그(isShowPopup)로 일관되게 처리한다.
  • JSON 파싱은 do/catch + JSONDecoder 패턴을 따른다.
  • 신규 코드에서 빈 catch는 금지하고, 최소한 로깅 또는 명시적 무시 사유를 남긴다.

로깅 규칙

  • 디버그 로그는 DEBUG_LOG, 오류 로그는 ERROR_LOG를 사용한다.
  • print는 임시 디버깅 목적 외 신규 코드에서 지양한다.

네트워크/헤더 규칙

  • 공통 Moya 플러그인(AuthPlugin, AcceptLanguagePlugin) 흐름을 유지한다.
  • 언어 헤더는 LanguageHeaderProvider.current를 기준으로 사용한다.

문자열/다국어

  • 신규 사용자 노출 문자열은 가능하면 I18n 경로를 우선 사용한다.
  • 다국어 기능 수정 시 Settings/Language 모듈과 Accept-Language 헤더 흐름을 함께 점검한다.

주석/문서화

  • 자명한 코드에는 주석을 남기지 않는다.
  • 복잡한 분기, 외부 제약, 부작용이 있는 로직에만 주석을 추가한다.