[CaloLink] - 전체 구조

sunghun kim·2025년 8월 12일

[캡디 - CaloLink]

목록 보기
5/9

구조

폴더 구조

.
└── CaloLink/
    ├── Source/
    │   ├── Application/               # 앱의 생명주기 및 전역 설정
    │   │   ├── AppDelegate.swift
    │   │   ├── SceneDelegate.swift
    │   │   └── DIContainer/           # 의존성 주입 컨테이너
    │   │
    │   ├── Data/                      # 데이터 소스 (네트워크, DB 등)
    │   │   ├── Network/               # 네트워크 통신 관련
    │   │   └── Repository/            # 데이터 저장소 구현체
    │   │
    │   ├── Domain/                    # 핵심 비즈니스 로직
    │   │   ├── Entity/                # 핵심 모델 객체
    │   │   ├── RepositoryProtocol/    # 데이터 저장소 인터페이스(프로토콜)
    │   │   └── UseCase/               # 비즈니스 로직 단위
    │   │
    │   └── Presentation/              # UI 계층
    │       ├── Common/                # 공통 UI 컴포넌트
    │       ├── MainScene/
    │       ├── SearchScene/
    │       ├── ListScene/
    │       └── DetailScene/
    │
    └── Resource/                      # 에셋 및 리소스
        ├── Assets.xcassets
        └── Info.plist

전체 폴더 구조는 이런식으로 구분하여 사용합니다.
초반 설정이 어렵다는 점과 파일이 많아진다는 점은 어쩔 수 없는 것 같습니다.

  • Application
    • 앱의 시작(AppDelegate, SceneDelegate)과 모든 의존성을 관리하고 주입하는 DIContainer가 위치합니다.
  • Data
    • 실제 데이터의 출처를 다루는 영역입니다.
    • Network 폴더에서는 URLSession을 사용한 REST API 통신을 구현하고,
    • Repository 폴더에서는 Domain 계층에 정의된 프로토콜을 준수하여 실제 데이터를 가져오는 로직을 구현합니다.
  • Domain
    • 프로젝트의 가장 핵심적인 비즈니스 규칙이 담기는 곳입니다.
    • UI나 데이터 소스에 대한 어떤 정보도 없이 순수한 Swift 코드로 작성됩니다.
  • Entity
    • 앱의 핵심 데이터 모델입니다. (예: Product)
  • RepositoryProtocol
    • 데이터 저장소에 대한 "규칙" 또는 "명세"입니다.
    • Domain은 이 프로토콜에만 의존합니다.
  • UseCase
    • "상품을 검색한다", "상품을 정렬한다"와 같이 사용자의 행동에 따른 비즈니스 로직의 단위입니다.
  • Presentation
    • 사용자에게 보여지는 UI 영역입니다.
    • 각 화면(Scene)별로 폴더를 나누고 내부적으로는 MVVM 패턴을 사용하여 View와 ViewModel로 역할을 분리합니다.

주요 UseCase 정의

UseCase는 사용자의 특정 목표나 앱의 비즈니스 로직 하나를 대표하는 독립적인 기능 단위입니다.
CaloLink 프로젝트의 핵심 기능들을 아래와 같이 UseCase로 정의합니다.

서버 통신 기반 UseCase

  • SearchProductsUseCase

    • 역할: 사용자의 검색어, 필터, 정렬 조건에 맞는 상품 목록을 서버에 요청하고 받아옵니다.
    • Input: SearchQuery (검색어, 필터 옵션, 정렬 옵션, 페이지 번호 등을 포함하는 객체)
    • Output: [Product] (상품 목록을 나타내는 엔티티 배열)
    • 데이터 출처: Server (API)
  • GetProductDetailUseCase

    • 역할: 사용자가 선택한 특정 상품의 상세 정보를 서버에 요청하고 받아옵니다.
    • Input: ProductID (상품의 고유 식별자)
    • Output: ProductDetail (상품의 상세 영양성분, 가격 정보 등을 포함하는 엔티티)
    • 데이터 출처: Server (API)

로컬 저장소 기반 UseCase (사용 안할 수도 있음!)

  • GetRecentKeywordsUseCase

    • 역할: 사용자의 기기에 저장된 '최근 검색어' 목록을 불러옵니다.
    • Input: 없음
    • Output: [String] (최근 검색어 문자열 배열)
    • 데이터 출처: Local (UserDefaults)
  • SaveRecentKeywordUseCase

    • 역할: 사용자가 검색한 키워드를 기기에 저장합니다. (중복된 키워드는 최신으로 올리고, 최대 개수를 유지하는 로직 포함)
    • Input: String (저장할 검색어)
    • Output: 없음
    • 데이터 출처: Local (UserDefaults)
  • ClearRecentKeywordsUseCase

    • 역할: 저장된 모든 최근 검색어 기록을 삭제합니다.
    • Input: 없음
    • Output: 없음
    • 데이터 출처: Local (UserDefaults)

전체 아키텍처 다이어그램

데이터 및 제어 흐름

  • View (UI): 사용자의 액션이 발생하면 ViewModel을 호출합니다.
  • ViewModel: 해당 액션에 맞는 UseCase를 실행시킵니다.
  • UseCase: 비즈니스 로직을 수행하고 필요한 데이터는 Repository Protocol을 통해 요청합니다.
  • Repository (구현체)
    • Domain의 요청을 받아 NetworkService를 통해 실제 데이터를 가져옵니다.
    • 서버에서 받은 데이터(DTO)를 Domain이 이해할 수 있는 Entity 모델로 변환하여 전달합니다.
  • NetworkService: URLSession을 사용하여 백엔드 서버와 통신하고, JSON 데이터를 받아옵니다.

이러한 단방향 의존성 구조는 각 계층을 독립적으로 개발하고 테스트할 수 있게 만들어주고 향후 API 서버가 변경되거나 새로운 데이터 소스가 추가되어도 Domain과 Presentation 계층의 코드 수정 없이 Data 계층만 교체하여 유연하게 대응할 수 있도록 합니다.

profile
기죽지않기

0개의 댓글