Skip to content

[#278] 무지성 로딩 플래그 난사를 줄인다#281

Merged
opficdev merged 4 commits intodevelopfrom
refactor/#278-isLoading
Mar 16, 2026
Merged

[#278] 무지성 로딩 플래그 난사를 줄인다#281
opficdev merged 4 commits intodevelopfrom
refactor/#278-isLoading

Conversation

@opficdev
Copy link
Owner

@opficdev opficdev self-assigned this Mar 16, 2026
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

이 Pull Request는 로딩 상태 관리를 위한 새로운 LoadingState 클래스를 도입하여 애플리케이션 전반의 로딩 플래그 관리를 간소화합니다. 이 변경으로 인해 여러 뷰모델에서 로딩 상태를 처리하는 상용구 코드가 크게 줄어들고, 즉시 및 지연 로딩 시나리오를 모두 지원하는 보다 일관되고 재사용 가능한 메커니즘이 제공됩니다. 이는 사용자 경험을 개선하고 코드 유지보수성을 높이는 데 기여합니다.

Highlights

  • 새로운 LoadingState 클래스 추가: 즉시(immediate) 및 지연(delayed) 모드를 통해 로딩 상태를 중앙에서 관리하는 새로운 LoadingState 클래스가 추가되었습니다.
  • 뷰모델 로딩 로직 통합: 여러 뷰모델(AccountViewModel, HomeViewModel, PushNotificationListViewModel, PushNotificationSettingsViewModel, SettingViewModel, TodayViewModel, TodoDetailViewModel, TodoListViewModel)에 LoadingState가 통합되었습니다.
  • 로딩 플래그 상용구 코드 감소: 기존의 수동 setLoading(true)setLoading(false) 호출이 새로운 LoadingState 클래스를 활용하는 beginLoadingendLoading 호출로 대체되어 상용구 코드가 줄었습니다.
  • HomeViewModel.LoadingTarget Hashable 채택: HomeViewModel.LoadingTarget 열거형이 Hashable 프로토콜을 준수하도록 변경되어 LoadingState와 함께 사용할 수 있게 되었습니다.
Changelog
  • DevLog/Presentation/Common/LoadingState.swift
    • 새로운 LoadingState 클래스가 추가되었습니다. 이 클래스는 immediatedelayed 로딩 모드를 지원하며, 여러 대상에 대한 로딩 상태를 관리하고 지연된 로딩 표시를 위한 태스크 스케줄링 기능을 포함합니다.
  • DevLog/Presentation/ViewModel/AccountViewModel.swift
    • LoadingState 인스턴스가 추가되었습니다.
    • 계정 연결 및 연결 해제 작업에서 setLoading 호출이 beginLoading(.delayed)endLoading(.delayed)로 대체되었습니다.
    • beginLoadingendLoading 헬퍼 메서드가 추가되었습니다.
  • DevLog/Presentation/ViewModel/HomeViewModel.swift
    • LoadingTarget 열거형이 Hashable 프로토콜을 준수하도록 변경되었습니다.
    • LoadingState 인스턴스가 추가되었습니다.
    • 할 일 추가, 최근 할 일 가져오기, 웹 페이지 추가/삭제/복원, 웹 페이지 가져오기 작업에서 setLoading 호출이 beginLoadingendLoading으로 대체되었습니다.
    • beginLoading(for:mode:)endLoading(for:mode:) 헬퍼 메서드가 추가되었습니다.
  • DevLog/Presentation/ViewModel/PushNotificationListViewModel.swift
    • LoadingState 인스턴스가 추가되었습니다.
    • 알림 가져오기, 삭제, 삭제 취소, 읽음/안 읽음 토글 작업에서 setLoading 호출이 beginLoadingendLoading으로 대체되었습니다.
    • beginLoadingendLoading 헬퍼 메서드가 추가되었습니다.
  • DevLog/Presentation/ViewModel/PushNotificationSettingsViewModel.swift
    • LoadingState 인스턴스가 추가되었습니다.
    • 푸시 알림 설정 가져오기 및 업데이트 작업에서 setLoading 호출이 beginLoadingendLoading으로 대체되었습니다.
    • beginLoadingendLoading 헬퍼 메서드가 추가되었습니다.
  • DevLog/Presentation/ViewModel/SettingViewModel.swift
    • LoadingState 인스턴스가 추가되었습니다.
    • 설정 화면의 인증 삭제 및 로그아웃 작업 로딩 상태 관리가 beginLoading(.delayed)endLoading(.delayed)로 전환되었습니다.
    • beginLoadingendLoading 헬퍼 메서드가 추가되었습니다.
  • DevLog/Presentation/ViewModel/TodayViewModel.swift
    • LoadingState 인스턴스가 추가되었습니다.
    • 오늘 할 일 화면의 할 일 가져오기, 완료, 고정 토글 작업 로딩 상태 관리가 beginLoadingendLoading으로 전환되었습니다.
    • beginLoadingendLoading 헬퍼 메서드가 추가되었습니다.
  • DevLog/Presentation/ViewModel/TodoDetailViewModel.swift
    • LoadingState 인스턴스가 추가되었습니다.
    • 할 일 상세 화면의 할 일 가져오기 및 업데이트 작업 로딩 상태 관리가 beginLoadingendLoading으로 전환되었습니다.
    • beginLoadingendLoading 헬퍼 메서드가 추가되었습니다.
  • DevLog/Presentation/ViewModel/TodoListViewModel.swift
    • LoadingState 인스턴스가 추가되었습니다.
    • 할 일 목록 화면의 할 일 가져오기, 다음 페이지 로드, 검색, 추가/업데이트, 완료 토글, 고정 토글, 삭제 취소 작업 로딩 상태 관리가 beginLoadingendLoading으로 전환되었습니다.
    • beginLoadingendLoading 헬퍼 메서드가 추가되었습니다.
Activity
  • 현재까지 이 Pull Request에 대한 인간 활동(댓글, 검토 등)은 없습니다.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

이 PR은 여러 ViewModel에 흩어져 있던 로딩 상태 관리 로직을 LoadingState라는 클래스로 추상화하여 코드의 재사용성과 유지보수성을 크게 향상시켰습니다. 특히 immediatedelayed 모드를 두어 짧은 작업에 대한 불필요한 로딩 표시기 깜빡임을 방지하려는 접근이 매우 좋습니다. 전반적으로 코드 변경 사항은 일관성 있고 깔끔하게 적용되었습니다.

다만, LoadingState의 핵심 로직에서 immediate 로딩과 delayed 로딩이 연달아 발생하는 특정 엣지 케이스에서 로딩 표시기가 깜빡이는 버그를 발견했습니다. 이에 대한 수정 제안을 코드에 직접 댓글로 남겼으니 확인 부탁드립니다. 이 부분을 수정하면 더욱 견고한 코드가 될 것입니다.

Comment on lines +141 to +145
if 0 < delayedCountByTarget[target, default: 0] {
update(false)
scheduleDelayedLoadingIfNeeded(for: target, update: update)
return
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

현재 구현에는 로직 결함이 있어 특정 시나리오에서 로딩 표시기가 깜빡이는 현상(flickering)이 발생할 수 있습니다.

문제 시나리오:

  1. begin(mode: .immediate)가 호출되어 로딩 표시기가 즉시 나타납니다.
  2. 짧은 시간 내에 begin(mode: .delayed)가 호출됩니다. delayed 작업을 위한 Task가 예약됩니다.
  3. end(mode: .immediate)가 호출됩니다. immediateCount가 0이 되므로 updateLoadingVisibility가 이 코드 블록으로 진입합니다.

현재 코드는 update(false)를 호출하여 로딩 표시기를 껐다가, 예약된 Task가 지연 시간 후에 완료되면 다시 켜게 됩니다. 이로 인해 불필요한 깜빡임이 발생하여 사용자 경험을 저해합니다.

해결 제안:
delayed 작업을 위한 Task가 이미 실행 중인지 확인하는 조건을 추가하여, immediate 로딩이 끝나더라도 delayed 로딩이 대기 중일 때는 로딩 표시기가 꺼지지 않도록 해야 합니다. 즉, 이미 Task가 있다면 update(false)를 호출하지 않아야 합니다.

Suggested change
if 0 < delayedCountByTarget[target, default: 0] {
update(false)
scheduleDelayedLoadingIfNeeded(for: target, update: update)
return
}
if 0 < delayedCountByTarget[target, default: 0] {
if delayedTaskByTarget[target] == nil {
update(false)
}
scheduleDelayedLoadingIfNeeded(for: target, update: update)
return
}

@opficdev
Copy link
Owner Author

/gemini review

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

이 PR은 여러 ViewModel에 분산되어 있던 로딩 상태 관리를 LoadingState라는 새로운 클래스로 중앙화하여 개선합니다. 이를 통해 코드 중복을 줄이고, 짧은 비동기 작업 시 로딩 인디케이터가 깜빡이는 현상을 방지하기 위해 지연된 로딩 표시 기능을 도입했습니다. 전반적으로 코드의 유지보수성과 사용자 경험을 향상시키는 좋은 변화입니다. 다만, undo 동작 처리 시 에러가 발생했을 때 로딩 상태가 제대로 해제되지 않는 버그가 발견되어 수정을 제안합니다.

Comment on lines 161 to 172
Task {
// defer을 통해 setLoading을 false로 제어하지 않는 이유
// send(.fetchNotifications)를 통해 false로 처리될 것이기 때문
send(.setLoading(true))

// endLoading(.delayed)를 defer로 두지 않는 이유
// send(.fetchNotifications)로 이어지는 즉시 로딩이 같은 isLoading을 이어서 제어해야 하기 때문
do {
try await undoDeleteUseCase.execute(notificationId)
} catch {
send(.setAlert(isPresented: true))
}

send(.fetchNotifications)
endLoading(.delayed)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

undoDeleteUseCase.execute(notificationId)에서 에러가 발생할 경우 catch 블록으로 이동하지만 endLoading(.delayed)가 호출되지 않아 로딩 상태가 계속 유지되는 버그가 있습니다. defer를 사용하여 Task가 어떤 경로로든 종료될 때 endLoading이 항상 호출되도록 보장하는 것이 좋습니다.

주석에 defer를 사용하지 않는 이유가 언급되어 있지만, LoadingState의 로직을 고려할 때 defer를 사용해도 fetchNotificationsimmediate 로딩이 올바르게 동작하여 문제가 없습니다. defer를 사용하면 코드의 안정성과 가독성이 향상됩니다.

            Task {
                defer { endLoading(.delayed) }
                do {
                    try await undoDeleteUseCase.execute(notificationId)
                    send(.fetchNotifications)
                } catch {
                    send(.setAlert(isPresented: true))
                }
            }

Comment on lines 235 to 246
Task {
// defer을 통해 setLoading을 false로 제어하지 않는 이유
// send(.refresh)를 통해 false로 처리될 것이기 때문
send(.setLoading(true))

// endLoading(.delayed)를 defer로 두지 않는 이유
// send(.refresh)로 이어지는 즉시 로딩이 같은 isLoading을 이어서 제어해야 하기 때문
do {
try await undoDeleteTodoUseCase.execute(todoId)
} catch {
send(.setAlert(true))
}

send(.refresh)
endLoading(.delayed)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

PushNotificationListViewModel에서 발견된 문제와 동일한 버그가 있습니다. undoDeleteTodoUseCase.execute(todoId)에서 에러가 발생하면 endLoading(.delayed)가 호출되지 않아 로딩 인디케이터가 멈출 수 있습니다. defer를 사용하여 endLoading이 항상 호출되도록 수정하는 것이 좋습니다.

            Task {
                defer { endLoading(.delayed) }
                do {
                    try await undoDeleteTodoUseCase.execute(todoId)
                    send(.refresh)
                } catch {
                    send(.setAlert(isPresented: true))
                }
            }

@opficdev opficdev merged commit 307733c into develop Mar 16, 2026
2 checks passed
@opficdev opficdev deleted the refactor/#278-isLoading branch March 16, 2026 06:11
opficdev added a commit that referenced this pull request Mar 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

무지성 로딩 플래그 난사를 줄인다

1 participant