SwiftUI 프롬프트 아키텍처 가이드라인

Minsang Kang·2025년 6월 25일

iOS Develop

목록 보기
11/12
post-thumbnail

cursor AI 를 사용하여 SwiftUI 로 신규 화면들, 기능들을 구현하고 있는 과정에서
아키텍처 상으로 공통적으로 계속 수정요청을 했던 부분들이 있었다.

View 에서 ViewModel 로 옮길 수 있을까?
여러 ViewModel 에서 사용될 것 같아서 UseCase로 옮길 수 있을까?
여러 View 에서 사용될 것 같아서 modifier 처럼 공통으로 사용할 수 있는 부분으로 수정해줄 수 있을까?

cursorAI 가 기본적으로 원하는 기능 혹은 오류 상황 등을 명확히 설명하면 context 상으로 다 추가하지 않더라고 정확히 이해하고 해결책을 제시하고는 합니다.
그리고 이 과정에서 추가로 생성이 필요한 파일도 생성해주기도 합니다.

다만 위 세 가지 처럼 View, ViewModel, UseCase, Modifier 등으로 분리시키는 관점에서는 약한 것 같아서
저만의 공통 아키텍처가 좀 잡힌 것 같아 이참에 프롬프트 가이드라인을 생성해봤습니다.

한글

프롬프트 아키텍처 가이드라인

이 가이드라인은 SwiftUI 애플리케이션의 아키텍처를 일관성 있고 확장 가능하게 유지하는 것을 목표로 합니다.

1. SwiftUI View

View는 UI 렌더링과 사용자 입력 처리에 집중합니다.

  • [관심사 분리] 복잡한 비즈니스 로직, 데이터 가공, 영구적인 상태 관리는 ViewModel에 위임합니다.
  • [상태 관리] View 자체의 일시적인 상태(@State)를 제외한 모든 상태는 ViewModel의 @Published 프로퍼티를 통해 전달받아 사용합니다.
  • [액션 전달] ViewModel에 데이터를 전달하거나 로직 실행을 요청할 때는 항상 viewModel.send(Action) 함수를 통해서만 전달합니다.
  • [재사용성] 여러 View에서 공통으로 사용되는 UI 로직이나 스타일은 별도의 View Component나 SwiftUI Modifier로 분리하여 재사용성을 높입니다.
  • [알림 처리] AlertSheet는 ViewModel의 @Published 상태 변수(예: showAlert, showShareSheet)에 바인딩하여 표시합니다. View는 알림의 내용이나 표시 여부를 직접 결정하지 않습니다.

2. ViewModel

ViewModel은 View를 위한 상태를 관리하고, View로부터 받은 액션을 처리합니다.

  • [관심사 분리] View와의 상호작용은 send(Action:) 메서드 하나로 통일하고, 그 외의 모든 내부 처리 함수는 private으로 선언하여 외부 노출을 최소화합니다.
  • [로직 분리] 여러 ViewModel에서 재사용될 수 있거나, 단위가 큰 비즈니스 로직(네트워크, 데이터베이스 등)은 UseCase로 분리하는 것을 우선적으로 고려합니다.
  • [오류 핸들링] UseCase나 내부 로직에서 발생한 오류는 do-catch 구문을 통해 처리합니다. 오류 발생 시, 사용자에게 피드백을 주기 위한 alertContent를 설정하고 showAlerttrue로 변경합니다.
  • [상태 전달] View에 전달해야 할 모든 상태(데이터, 알림 내용, 시트 표시 여부 등)는 @Published 프로퍼티를 통해 전달합니다.

3. UseCase

UseCase는 특정 비즈니스 로직을 수행하는 단일 책임을 가집니다.

  • [구조] 명확한 인터페이스를 위해 protocol을 정의하고, 실제 구현체는 Default...UseCase로 작성합니다. UseCase 내에서 발생할 수 있는 오류는 별도의 Error 열거형으로 상세하게 정의합니다.
  • [역할] 로직 실행은 execute 함수를 통해 이루어지며, 필요한 input을 받아 처리 후 output을 반환합니다.
  • [오류 핸들링] 로직 수행 중 실패할 수 있는 경우, 반환 값을 Optional로 처리하기보다 throws를 사용하여 오류가 발생했음을 명확하게 알리고, ViewModel 단에서 catch하여 처리하도록 구현합니다.

4. Localized (현지화)

모든 사용자 대상 문자열은 현지화를 고려하여 관리합니다.

  • [파일 구조] 모든 현지화 문자열은 TLRKey, TLRko, TLRen, TLRzh 파일에서 중앙 관리합니다.
  • [키 정의] 새로운 문자열 키는 TLRKey 파일 내 열거형(enum)에 case로 추가합니다. 키 이름은 {대분류}_{요소}_{상세설명} 규칙을 따릅니다. (예: Common_Popup_SaveFailed)
  • [값 추가] TLRko에 기준이 되는 한국어 문장을 추가하고, 이를 바탕으로 TLRen(영어), TLRzh(중국어 간체)에 번역된 값을 추가합니다.
  • [사용법] 코드에서는 Localized.string(.yourKey) 형태로 키를 사용하여 현지화된 문자열을 가져옵니다.

영문

Architecture Guidelines for Prompts

This guideline aims to maintain a consistent and scalable architecture for the SwiftUI application.

1. SwiftUI View

The View's primary responsibility is to render the UI and handle user input.

  • [Separation of Concerns] Delegate complex business logic, data processing, and persistent state management to the ViewModel.
  • [State Management] Except for transient view-specific state (@State), all state should be received from the ViewModel's @Published properties.
  • [Action Forwarding] Always use the viewModel.send(Action) function to forward data or request logic execution from the ViewModel.
  • [Reusability] Enhance reusability by extracting common UI logic or styles, used across multiple Views, into separate View Components or SwiftUI Modifiers.
  • [Alert & Sheet Handling] Display Alerts and Sheets by binding to @Published state variables from the ViewModel (e.g., showAlert, showShareSheet). The View should not decide the content or the visibility of these presentations itself.

2. ViewModel

The ViewModel manages the state for the View and processes actions received from it.

  • [Separation of Concerns] Unify all interactions from the View through a single send(Action:) method. All other internal processing functions should be declared private to minimize exposure.
  • [Logic Abstraction] Prioritize abstracting reusable or large-scale business logic (e.g., networking, database operations) into UseCases.
  • [Error Handling] Handle errors from UseCases or internal logic using a do-catch statement. Upon catching an error, set the alertContent and change showAlert to true to provide feedback to the user.
  • [State Exposure] Expose all state required by the View (e.g., data, alert content, sheet visibility) through @Published properties.

3. UseCase

A UseCase has a single responsibility to perform a specific piece of business logic.

  • [Structure] Define a protocol for a clear interface and name the concrete implementation Default...UseCase. Define potential errors within a dedicated Error enum for clarity.
  • [Role] Logic is executed via an execute function that takes an input and returns an output.
  • [Error Handling] For operations that can fail, prefer throws to signal an error over returning an Optional. This ensures errors are explicitly handled via catch in the ViewModel.

4. Localization

All user-facing strings must be managed with localization in mind.

  • [File Structure] All localized strings are centrally managed in TLRKey, TLRko, TLRen, and TLRzh files.
  • [Key Definition] Add new string keys as cases within the enum in the TLRKey file. Key names must follow the {Scope}_{Component}_{Description} convention (e.g., Common_Popup_SaveFailed).
  • [Value Addition] Add the base Korean sentence to TLRko, then add its English and Simplified Chinese translations to TLRen and TLRzh respectively.
  • [Usage] In code, use Localized.string(.yourKey) to retrieve the localized string.

Cursor AI 의 가이드라인 추가

위 영문 내용을 토대로 mdc 가이드라인은 추가해봤습니다

그러면 이렇게 chat 상에서 context 로 추가하면 가이드라인 지침을 추가할 수 있습니다

프롬프트

아래는 가이드라인 생성을 위해 요청했던 프롬프트 문장입니다.

이제 만족스럽구만

근데 앞으로 계속 이렇게 리펙토링에 대해 내가 요구하는 상황들이 점점 많아질 것 같은데 공통적인 패턴이 눈에 보이거든
이를 cursor ai 인 너한테 요청하는 프롬프트상의 "지침"으로 추가하고자 하는데 정리해줄 수 있을까?

내가 느낀 부분들은 다음과 같아.

# SwiftUI View
- [관심사 분리] 모든 처리를 View 에서 하려고 하면 안된다. 관심사 분리 관점에서 View에 해당하는지 고려해야 한다.
- [관심사 분리] ViewModel 의 @Published 프로퍼티로 관리 가능한지 고려해야 한다.
- [관심사 분리] ViewModel 로 요청이 필요한 경우 항상 viewModel.send 함수를 통해 요청해야 한다.
- [Modifier] View 에서 처리해야 하지만 여러 View 에서 사용될 수 있는 기능이라면 Modifier 로 뺄 수 있는지 고려해야 한다.
- [Alert] Alert 가 필요한 경우는 viewModel 의 showAlert, alertContent 를 토대로 alert를 구현한다.

# ViewModel
- [관심사 분리] View 로부터 요청은 항상 send 함수를 통해 요청받아야 한다. 그 외는 private 함수로 관리한다.
- [관심사 분리] ViewModel 에서 처리해야 하지만 여러 ViewModel 에서 사용될 수 있는 기능이라면 UseCase 로 뺄 수 있는지 고려해야 한다.
- [오류 핸들링] UseCase로부터, 혹은 ViewModel 내에서 catch 문을 사용하여 오류를 받게 되면 alert를 표시하도록 구현한다.
- [Alert] Alert 가 필요한 경우는 showAlert, alertContent 프로퍼티를 통해 View로 전달한다.

# UseCase
- [관심사 분리] UseCase 는 프로토콜과 Error 를 지녀 execute 함수를 통해 input -> output 역할을 담당한다.
- [오류 핸들링] throws 를 사용하여 오류가 발생되면 ViewModel 단에서 catch 되도록 구현한다.

# Localized
- [파일들] 로컬라이징 문구들은 TLRKey, TLRko, TLRen, TLRzh 로 관리한다.
- [사용] 로컬라이징 문구 사용은 Localized.string(key값) 형식으로 사용한다.
- [key] key 값 추가는 TLRKey 파일 내 case 문을 추가한다. key 값 명칭 구조는 {큰범위}_{요소}_{설명} 에 따른다.
- [value] value 값 추가는 한국어 문장을 기준으로 영문장, 중국어 간체 문장으로 번역하여 각각 TLRko, TLRen,TLRzh 에 반영한다.

-> 가이드라인 생성

profile
 iOS Developer

0개의 댓글