[Feat] 루틴 등록 / 수정 로직 구현#33
Conversation
- 루틴 생성 추가 - 루틴 수정 추가 - 루틴 단건 조회 추가
- 루틴 요약, 서브 루틴 요약 엔티티 생성
Walkthrough이 변경 사항은 루틴 생성, 조회, 수정 기능의 전체적인 도메인, 데이터소스, 프레젠테이션 계층에 걸친 확장 및 리팩터링을 포함합니다. 새로운 DTO와 엔티티, Enum이 추가되고, 프로토콜 및 레포지토리, 유스케이스에 관련 메서드가 도입되었습니다. 뷰와 뷰모델은 루틴 편집/수정 플로우를 지원하도록 대폭 확장되었습니다. Changes
Sequence Diagram(s)sequenceDiagram
participant View as RoutineCreationView
participant ViewModel as RoutineCreationViewModel
participant UseCase as RoutineUseCase
participant Repo as RoutineRepository
View->>ViewModel: action(input: .fetchRoutine(id))
ViewModel->>UseCase: fetchRoutine(routineId)
UseCase->>Repo: fetchRoutine(routineId)
Repo-->>UseCase: RoutineEntity?
UseCase-->>ViewModel: RoutineEntity?
ViewModel-->>View: 상태 업데이트
View->>ViewModel: action(input: .registerRoutine)
ViewModel->>UseCase: saveRoutine(routineSummary, subRoutineSummaries, deletedSubRoutineSummaries)
UseCase->>Repo: createRoutine or updateRoutine
Repo-->>UseCase: (완료)
UseCase-->>ViewModel: (완료)
ViewModel-->>View: (UI 갱신)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~40분 Poem
Note ⚡️ Unit Test Generation is now available in beta!Learn more here, or try it out under "Finishing Touches" below. ✨ Finishing Touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
Documentation and Community
|
There was a problem hiding this comment.
Actionable comments posted: 4
🔭 Outside diff range comments (1)
Projects/Domain/Sources/Entity/SubRoutineEntity.swift (1)
18-28: 초기화자 파라미터 일관성 검토 필요프로퍼티는 옵셔널(
String?)이지만 초기화자 파라미터는 non-optional(String)입니다. 이는 혼란을 야기할 수 있습니다.초기화자도 옵셔널 파라미터를 받도록 수정하는 것을 고려해보세요:
public init( - subRoutineId: String, + subRoutineId: String?, historySeq: Int, subRoutineName: String, modifiedYn: Bool, sortOrder: Int, routineCompletionId: Int?, completeYn: Bool, routineType: String ) {
🧹 Nitpick comments (11)
Projects/Domain/Sources/Entity/Untitled.swift (1)
1-8: 불필요한 빈 파일 및 의미 없는 파일명 정리 권장현재 파일은 주석만 존재하며 실제 코드가 없습니다.
Untitled.swift라는 이름도 도메인 계층의 역할을 설명하지 못합니다. 의도된 구현이 없다면 컴파일에는 영향이 없더라도 레포지터리에 불필요한 잡음을 남기게 됩니다.
- 구현 계획이 없다면 파일을 제거하세요.
- 추후 사용 예정이라면 파일명과 타입명을 도메인 개념에 맞게 명확히 하고, 최소한의 스켈레톤(
struct/class) 선언을 추가해 주세요.Projects/Domain/Sources/Entity/Enum/WeekType.swift (1)
1-7: 파일명과 타입명 불일치 수정 필요파일명이
Week.swift이지만 내부에 정의된 타입은WeekType입니다. 일관성을 위해 파일명을WeekType.swift로 변경하는 것이 좋겠습니다.-// Week.swift +// WeekType.swiftProjects/DataSource/Sources/Common/Extension/Encodable+.swift (1)
10-18: 에러 처리 개선 고려현재 구현에서는 인코딩 실패 시 빈 딕셔너리를 반환하여 오류를 숨길 수 있습니다. 네트워크 요청에서 사용될 때 예상치 못한 동작을 유발할 수 있습니다.
다음과 같은 개선 방안을 고려해보세요:
extension Encodable { var dictionary: [String: Any] { guard let data = try? JSONEncoder().encode(self), let dictionary = try? JSONSerialization.jsonObject(with: data) as? [String: Any] - else { return [:] } + else { + print("⚠️ Failed to convert \(type(of: self)) to dictionary") + return [:] + } return dictionary } }또는 throwing 버전을 추가로 제공하는 것도 고려할 수 있습니다.
Projects/DataSource/Sources/DTO/SubRoutineUpdateDTO.swift (1)
8-12: DTO 구조는 적절하지만 도메인 엔티티와의 차별화를 고려해보세요.API 통신을 위한 DTO로서 옵셔널 프로퍼티들이 적절하게 정의되었습니다. 하지만
SubRoutineSummaryEntity와 구조가 거의 동일하여 PR 목표에서 언급된 tight coupling 우려가 있습니다.향후 서버 V2 리팩터링 시 도메인 엔티티와 DTO 간의 명확한 책임 분리를 고려해보세요. Repository 계층에서 매핑 로직을 통해 API 변경이 도메인에 미치는 영향을 최소화할 수 있습니다.
Projects/DataSource/Sources/DTO/RoutineCreationDTO.swift (1)
2-2: 파일명 오타를 수정해주세요.파일명에 오타가 있습니다: "RoutienCreationDTO.swift" → "RoutineCreationDTO.swift"
Projects/DataSource/Sources/Endpoint/RoutineEndpoint.swift (1)
20-27: path 속성에서 더 명시적인 케이스 처리를 고려해보세요.현재
default케이스를 사용하고 있는데, 향후 새로운 케이스가 추가될 때의 실수를 방지하기 위해 명시적으로 각 케이스를 나열하는 것을 고려해보세요.var path: String { switch self { + case .createRoutine, .fetchRoutines, .updateRoutine: + baseURL case .fetchRoutine(let routineId): "\(baseURL)/\(routineId)" - default: - baseURL } }Projects/Domain/Sources/UseCase/Routine/RoutineUseCase.swift (1)
18-21: 변수명 오타를 수정해주세요.Line 19에서
routineEnity는routineEntity로 수정해야 합니다.- let routineEnity = try await routineRepository.fetchRoutine(routineId: routineId) - return routineEnity + let routineEntity = try await routineRepository.fetchRoutine(routineId: routineId) + return routineEntityProjects/Presentation/Sources/RoutineCreation/ViewModel/RoutineCreationViewModel.swift (4)
121-121: TODO 주석 해결 필요에러 처리에 대한 TODO 주석이 있습니다. 적절한 에러 처리 로직 구현이 필요합니다.
에러 처리 구현을 도와드릴까요? 다음과 같은 접근을 제안드립니다:
- 네트워크 에러, 파싱 에러 등을 구분하여 처리
- 사용자에게 적절한 피드백 제공
- 에러 발생 시 이전 화면으로 돌아가거나 재시도 옵션 제공
Also applies to: 150-151
161-161: 매직 넘버 상수화 필요서브루틴 개수 제한(3)이 하드코딩되어 있습니다.
+private enum Constants { + static let maxSubRoutineCount = 3 +} -guard subRoutines.count <= 3 else { return } +guard subRoutines.count <= Constants.maxSubRoutineCount else { return }
172-187: 서브루틴 삭제 시 sortOrder 재정렬 고려서브루틴을 삭제한 후 남은 서브루틴들의 sortOrder가 연속적이지 않을 수 있습니다. 이는 추후 정렬 시 문제가 될 수 있습니다.
삭제 후 남은 서브루틴들의 sortOrder를 재정렬하는 로직을 추가하는 것을 고려해보세요:
subRoutines.remove(at: index) // sortOrder 재정렬 subRoutines = subRoutines.enumerated().map { index, entity in SubRoutineSummaryEntity( subRoutineId: entity.subRoutineId, subRoutineName: entity.subRoutineName, sortOrder: index + 1 ) }
66-73: 엔티티 사용에 대한 아키텍처 고려사항PR 목표에서 언급하신 대로, 프레젠테이션 레이어에서 도메인 엔티티를 직접 사용하는 것은 결합도를 높일 수 있습니다. 향후 서버 API 변경 시 영향을 최소화하기 위해 다음을 고려해보세요:
- 프레젠테이션 레이어 전용 모델 도입
- 도메인 엔티티를 프레젠테이션 모델로 매핑하는 mapper 사용
- 이를 통해 API 변경이 프레젠테이션 레이어까지 전파되는 것을 방지
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (23)
Projects/DataSource/Sources/Common/Extension/Encodable+.swift(1 hunks)Projects/DataSource/Sources/DTO/RoutineCreationDTO.swift(1 hunks)Projects/DataSource/Sources/DTO/RoutineResponseDTO.swift(1 hunks)Projects/DataSource/Sources/DTO/RoutineUpdateDTO.swift(1 hunks)Projects/DataSource/Sources/DTO/SubRoutineUpdateDTO.swift(1 hunks)Projects/DataSource/Sources/Endpoint/RoutineEndpoint.swift(3 hunks)Projects/DataSource/Sources/Repository/RoutineRepository.swift(2 hunks)Projects/Domain/Sources/Entity/Enum/WeekType.swift(1 hunks)Projects/Domain/Sources/Entity/RoutineEntity.swift(3 hunks)Projects/Domain/Sources/Entity/RoutineSummaryEntity.swift(1 hunks)Projects/Domain/Sources/Entity/SubRoutineEntity.swift(1 hunks)Projects/Domain/Sources/Entity/SubRoutineSummaryEntity.swift(1 hunks)Projects/Domain/Sources/Entity/Untitled.swift(1 hunks)Projects/Domain/Sources/Protocol/Repository/RoutineRepositoryProtocol.swift(1 hunks)Projects/Domain/Sources/Protocol/UseCase/RoutineUseCaseProtocol.swift(1 hunks)Projects/Domain/Sources/UseCase/Routine/RoutineUseCase.swift(1 hunks)Projects/Presentation/Sources/Common/PresentationDependencyAssembler.swift(1 hunks)Projects/Presentation/Sources/Home/Model/MainRoutine.swift(1 hunks)Projects/Presentation/Sources/Home/Model/SubRoutine.swift(1 hunks)Projects/Presentation/Sources/Home/View/HomeView.swift(1 hunks)Projects/Presentation/Sources/Home/ViewModel/HomeViewModel.swift(1 hunks)Projects/Presentation/Sources/RoutineCreation/View/RoutineCreationView.swift(3 hunks)Projects/Presentation/Sources/RoutineCreation/ViewModel/RoutineCreationViewModel.swift(11 hunks)
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: onboardingrecommendedroutineview에서 viewwillappear에 registeronboarding 호출하는 것이 적절한 이유: 사용자가 이전 페이지에서 ...
Learnt from: choijungp
PR: YAPP-Github/Bitnagil-iOS#19
File: Projects/Presentation/Sources/Onboarding/View/OnboardingRecommendedRoutineView.swift:57-59
Timestamp: 2025-07-16T09:21:15.038Z
Learning: OnboardingRecommendedRoutineView에서 viewWillAppear에 registerOnboarding 호출하는 것이 적절한 이유: 사용자가 이전 페이지에서 온보딩 선택지를 변경한 후 돌아올 때 새로운 선택지로 다시 등록해야 하기 때문. 홈 뷰에서는 이 뷰로 돌아올 수 없어서 중복 호출 문제가 발생하지 않음.
Applied to files:
Projects/Presentation/Sources/Common/PresentationDependencyAssembler.swiftProjects/Presentation/Sources/Home/View/HomeView.swiftProjects/Presentation/Sources/RoutineCreation/View/RoutineCreationView.swift
📚 Learning: choijungp의 homeviewmodel에서 fetchroutines(for date: date) 메서드는 기존 캐시 범위를 확장하는 것이 아니라, 요청된 날짜 주변의 새로운 ...
Learnt from: choijungp
PR: YAPP-Github/Bitnagil-iOS#31
File: Projects/Presentation/Sources/Home/ViewModel/HomeViewModel.swift:97-103
Timestamp: 2025-08-01T06:38:18.687Z
Learning: choijungp의 HomeViewModel에서 fetchRoutines(for date: Date) 메서드는 기존 캐시 범위를 확장하는 것이 아니라, 요청된 날짜 주변의 새로운 데이터 청크를 가져오기 위해 oldestDate와 latestDate를 모두 업데이트한다. 과거 날짜 요청 시에는 해당 날짜의 1주 전~1일 전, 미래 날짜 요청 시에는 해당 날짜의 1일 후~1주 후 범위로 설정한다.
Applied to files:
Projects/Presentation/Sources/Home/ViewModel/HomeViewModel.swiftProjects/Presentation/Sources/Home/View/HomeView.swiftProjects/Domain/Sources/Protocol/Repository/RoutineRepositoryProtocol.swiftProjects/Domain/Sources/UseCase/Routine/RoutineUseCase.swiftProjects/DataSource/Sources/Repository/RoutineRepository.swiftProjects/Presentation/Sources/RoutineCreation/ViewModel/RoutineCreationViewModel.swift
📚 Learning: baseviewcontroller의 viewdidload() 메서드에서 이미 configureattribute(), configurelayout(), bind()를 호출하므로, 하...
Learnt from: choijungp
PR: YAPP-Github/Bitnagil-iOS#19
File: Projects/Presentation/Sources/Login/View/TermsAgreementView.swift:44-46
Timestamp: 2025-07-16T09:09:13.869Z
Learning: BaseViewController의 viewDidLoad() 메서드에서 이미 configureAttribute(), configureLayout(), bind()를 호출하므로, 하위 클래스에서 super.viewDidLoad()를 호출하면 이 메서드들이 자동으로 호출된다. 따라서 하위 클래스에서 추가로 호출할 필요가 없다.
Applied to files:
Projects/Presentation/Sources/RoutineCreation/View/RoutineCreationView.swift
🧬 Code Graph Analysis (6)
Projects/Presentation/Sources/Common/PresentationDependencyAssembler.swift (1)
Projects/Shared/Sources/DIContainer/DIContainer.swift (2)
register(14-16)resolve(18-25)
Projects/Presentation/Sources/Home/ViewModel/HomeViewModel.swift (1)
Projects/Presentation/Sources/Home/Model/MainRoutine.swift (1)
toMainRoutine(21-35)
Projects/DataSource/Sources/DTO/RoutineResponseDTO.swift (1)
Projects/DataSource/Sources/DTO/SubRoutineResponseDTO.swift (1)
toSubRoutineEntity(22-32)
Projects/Domain/Sources/Protocol/UseCase/RoutineUseCaseProtocol.swift (3)
Projects/Domain/Sources/UseCase/Routine/RoutineUseCase.swift (3)
fetchRoutine(18-21)fetchRoutines(23-29)saveRoutine(31-44)Projects/DataSource/Sources/Repository/RoutineRepository.swift (2)
fetchRoutine(26-31)fetchRoutines(33-43)Projects/Presentation/Sources/RoutineCreation/ViewModel/RoutineCreationViewModel.swift (1)
fetchRoutine(118-153)
Projects/Domain/Sources/Protocol/Repository/RoutineRepositoryProtocol.swift (3)
Projects/Domain/Sources/UseCase/Routine/RoutineUseCase.swift (4)
createRoutine(46-48)fetchRoutine(18-21)fetchRoutines(23-29)updateRoutine(50-72)Projects/DataSource/Sources/Repository/RoutineRepository.swift (4)
createRoutine(13-24)fetchRoutine(26-31)fetchRoutines(33-43)updateRoutine(45-64)Projects/Presentation/Sources/Home/ViewModel/HomeViewModel.swift (2)
fetchRoutines(85-108)fetchRoutines(110-125)
Projects/DataSource/Sources/Repository/RoutineRepository.swift (3)
Projects/Domain/Sources/UseCase/Routine/RoutineUseCase.swift (3)
createRoutine(46-48)fetchRoutine(18-21)updateRoutine(50-72)Projects/DataSource/Sources/NetworkService/NetworkService.swift (1)
request(24-47)Projects/DataSource/Sources/DTO/RoutineResponseDTO.swift (1)
toRoutineEntity(28-42)
🪛 SwiftLint (0.57.0)
Projects/Presentation/Sources/RoutineCreation/ViewModel/RoutineCreationViewModel.swift
[Warning] 121-121: TODOs should be resolved (- routine fetch 실패 시 처리 방안 필요 ...)
(todo)
[Warning] 150-150: TODOs should be resolved (- 요기도 마찬가지 (ViewModel 공통 todo))
(todo)
🔇 Additional comments (30)
Projects/Domain/Sources/Entity/Enum/WeekType.swift (1)
8-16: 타입 안전성 개선이 잘 구현됨문자열 배열 대신 강타입 enum을 사용하여 요일 표현의 타입 안전성을 크게 개선했습니다.
String과CaseIterable프로토콜 준수도 적절하며, 대문자 raw value 형식도 API 통신에 적합합니다.Projects/Domain/Sources/Entity/SubRoutineEntity.swift (1)
9-9: 옵셔널 처리가 적절함
subRoutineId를 옵셔널로 변경한 것은 생성/수정 플로우를 지원하기 위한 적절한 설계입니다. 새로운 서브루틴 생성 시에는 ID가 없고, 수정 시에는 ID가 필요한 시나리오를 잘 반영했습니다.Projects/Presentation/Sources/Home/View/HomeView.swift (1)
532-532: 루틴 편집 플로우 구현이 적절함기존 루틴 편집을 위해
routineId파라미터를 전달하는 구현이 깔끔합니다. PR 목표에서 언급한 통합된 저장/편집 접근 방식과 잘 일치하며, 프레젠테이션 레이어에서 도메인 레이어로 적절히 책임을 위임하고 있습니다.Projects/Presentation/Sources/Home/ViewModel/HomeViewModel.swift (1)
101-101: 방어적 프로그래밍 패턴이 잘 적용됨
compactMap을 사용하여 변환에 실패한 루틴들을 필터링하는 것은 좋은 방어적 프로그래밍 패턴입니다.MainRoutine.toMainRoutine()이 옵셔널을 반환하도록 변경된 것과 일치하며, 유효하지 않은 데이터로 인한 UI 오류를 방지합니다.Projects/DataSource/Sources/DTO/RoutineResponseDTO.swift (1)
29-37: 서브루틴 정렬 로직이 올바르게 구현되었습니다.
sortOrder기준으로 오름차순 정렬 후 엔티티로 변환하는 로직이 적절합니다. 이를 통해 API 응답에서 순서가 보장되지 않더라도 일관된 순서로 서브루틴을 제공할 수 있습니다.Projects/Presentation/Sources/Home/Model/SubRoutine.swift (1)
18-20: 안전한 옵셔널 처리가 적절하게 구현되었습니다.
subRoutineId가 옵셔널로 변경됨에 따라 guard 문을 사용한 안전한 변환 로직이 추가되었습니다. 새로 생성되는 서브루틴의 경우 ID가 없을 수 있으므로 이러한 처리가 필요합니다.Projects/Presentation/Sources/Common/PresentationDependencyAssembler.swift (1)
69-74: 의존성 주입 설정이 일관성 있게 구현되었습니다.
RoutineCreationViewModel에RoutineUseCaseProtocol의존성을 주입하는 로직이 다른 ViewModel들과 동일한 패턴으로 구현되어 일관성을 유지하고 있습니다.Projects/DataSource/Sources/DTO/RoutineUpdateDTO.swift (1)
8-14: LGTM!DTO 구조체가 명확하고 간결하게 구현되었습니다. Codable 프로토콜 준수로 네트워크 통신에 적합하며, 불변 프로퍼티 사용으로 데이터 무결성을 보장합니다.
Projects/Presentation/Sources/RoutineCreation/View/RoutineCreationView.swift (4)
80-95: 등록/수정 모드 구분 로직이 잘 구현되었습니다.routineId 파라미터를 통해 등록과 수정 모드를 명확히 구분하고, 수정 모드일 때 자동으로 기존 루틴 데이터를 로드하는 로직이 적절합니다.
103-103: 동적 네비게이션 타이틀 설정이 적절합니다.모드에 따라 "루틴 등록"과 "루틴 수정"을 구분하여 사용자 경험을 개선했습니다.
178-178: 버튼 타이틀 일관성이 유지되었습니다.네비게이션 타이틀과 일치하는 버튼 텍스트로 UI 일관성을 유지했습니다.
527-532: registerButton 액션 연결이 적절합니다.뷰모델의 registerRoutine 액션과 명확하게 연결되어 있습니다.
Projects/Presentation/Sources/Home/Model/MainRoutine.swift (2)
21-27: 안전한 변환 로직이 잘 구현되었습니다.옵셔널 반환과 guard 절을 사용하여 실패 가능한 변환을 안전하게 처리했습니다. 모든 서브루틴이 성공적으로 변환되었는지 확인하는 로직도 적절합니다.
33-33: WeekType enum과의 매핑이 정확합니다.rawValue를 사용한 매핑으로 타입 안전성을 유지하면서 적절히 변환하고 있습니다.
Projects/DataSource/Sources/DTO/RoutineCreationDTO.swift (1)
8-13: LGTM!루틴 생성을 위한 DTO 구조체가 명확하고 적절하게 구현되었습니다. Codable 준수로 네트워크 통신에 적합합니다.
Projects/Domain/Sources/Entity/RoutineSummaryEntity.swift (1)
8-27: 도메인 엔티티가 잘 설계되었습니다.
- Public 접근 제어자로 모듈 간 사용이 가능합니다
- 초기화 시 String 배열을 WeekType으로 안전하게 변환하는 로직이 적절합니다
- compactMap을 사용하여 실패한 변환을 안전하게 처리합니다
- nil 기본값 처리로 견고성을 확보했습니다
Projects/Domain/Sources/Protocol/UseCase/RoutineUseCaseProtocol.swift (1)
11-19: 프로토콜 설계가 잘 되어 있습니다.새로 추가된 메서드들이 적절하게 설계되었습니다:
fetchRoutine이 옵셔널을 반환하여 루틴이 존재하지 않는 경우를 적절히 처리saveRoutine이 생성과 수정을 모두 처리할 수 있도록 설계- 삭제된 서브루틴을 별도로 처리하여 업데이트 로직을 명확히 분리
Projects/DataSource/Sources/Endpoint/RoutineEndpoint.swift (2)
9-12: 새로운 엔드포인트 케이스들이 적절하게 추가되었습니다.각 케이스가 명확한 목적을 가지고 있고 DTO 타입과 적절히 연결되어 있습니다.
60-68: Encodable 확장에var dictionary구현 확인됨
Projects/DataSource/Sources/Common/Extension/Encodable+.swift파일에서Encodable프로토콜 확장으로var dictionary: [String: Any]가 구현되어 있습니다.- 따라서
RoutineEndpoint.swift의routine.dictionary사용은 유효하며, 추가 조치가 필요 없습니다.Projects/Domain/Sources/Protocol/Repository/RoutineRepositoryProtocol.swift (1)
10-33: 레포지토리 프로토콜이 잘 설계되었습니다.새로 추가된 메서드들이 도메인 계층의 요구사항을 적절히 반영하고 있습니다:
- 도메인 엔티티를 사용하여 계층 간 분리가 잘 되어 있음
- 메서드 시그니처가 유스케이스와 일관성 있게 설계됨
- 한글 문서화가 명확하고 이해하기 쉬움
Projects/Domain/Sources/Entity/RoutineEntity.swift (3)
9-9: routineId를 옵셔널로 변경한 것이 적절합니다.새로운 루틴의 경우 아직 ID가 할당되지 않은 상태를 명확히 표현할 수 있습니다.
12-12: WeekType 열거형 사용으로 타입 안전성이 향상되었습니다.문자열 배열 대신 WeekType 열거형을 사용하여 요일 데이터의 타입 안전성이 크게 개선되었습니다.
32-37: WeekType 변환 로직이 안전하게 구현되었습니다.
compactMap과 nil 병합 연산자를 사용하여 변환 실패 시에도 안전하게 빈 배열로 처리하는 로직이 좋습니다.Projects/Domain/Sources/UseCase/Routine/RoutineUseCase.swift (2)
31-44: saveRoutine 메서드의 분기 처리가 명확합니다.routineId의 존재 여부로 생성과 수정을 구분하는 로직이 직관적이고 주석도 명확합니다. 프레젠테이션 계층에서 단일 메서드로 호출할 수 있어 사용성이 좋습니다.
50-72: updateRoutine의 서브루틴 처리 로직이 잘 구현되었습니다.복잡한 업데이트 로직을 단계별로 처리하고 있습니다:
- 수정된 서브루틴의 정렬 순서 재계산 (1부터 시작)
- 삭제된 서브루틴의 name과 sortOrder를 nil로 설정
- 두 배열을 병합하여 단일 요청으로 처리
이 접근 방식은 API 호출 횟수를 최소화하면서도 모든 변경사항을 처리할 수 있어 효율적입니다.
Projects/DataSource/Sources/Repository/RoutineRepository.swift (2)
13-24: LGTM!
createRoutine메서드가 올바르게 구현되었습니다.compactMap을 사용하여 nil 값을 필터링하고, DTO 변환이 적절하게 처리되었습니다.
26-31: LGTM!
fetchRoutine메서드가 안전하게 구현되었습니다. 옵셔널 처리와 DTO-Entity 변환이 적절합니다.Projects/Presentation/Sources/RoutineCreation/ViewModel/RoutineCreationViewModel.swift (3)
206-219: LGTM!switch 문을 사용하여 반복 타입 설정 로직이 더 명확해졌습니다.
245-261: LGTM!검증 로직이 포괄적이고 잘 구성되어 있습니다. 특히
allSatisfy를 사용한 서브루틴 이름 검증이 우아합니다.
275-275: 시간 포맷 일관성 확인 완료
DateType.time의formatString은"HH:mm:ss"로 정의되어 있어,allDay의 하드코딩 값("00:00:00")과 일치합니다. 내부 변환 로직은 올바르게 작동하나, 서버 API 스펙이 해당 포맷을 요구하는지 최종 확인 부탁드립니다.
| func updateRoutine(routineSummary: RoutineSummaryEntity, subRoutineSummaries: [SubRoutineSummaryEntity]) async throws { | ||
| guard let routineId = routineSummary.routineId else { return } |
There was a problem hiding this comment.
routineId가 nil일 때 조용히 실패하는 문제
현재 routineId가 nil일 경우 아무런 오류 없이 메서드가 종료됩니다. 이는 호출자가 업데이트 실패를 인지하지 못하게 할 수 있습니다.
다음과 같이 오류를 던지는 것을 고려해보세요:
-guard let routineId = routineSummary.routineId else { return }
+guard let routineId = routineSummary.routineId else {
+ throw RoutineRepositoryError.missingRoutineId
+}또는 메서드 시그니처를 변경하여 옵셔널 결과를 반환하거나, 완료 상태를 나타내는 Bool을 반환하는 것도 고려해볼 수 있습니다.
Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In Projects/DataSource/Sources/Repository/RoutineRepository.swift at lines
45-46, the method updateRoutine silently returns when routineId is nil, causing
callers to miss update failures. Modify the method to throw a specific error
when routineId is nil instead of returning quietly. Define a suitable error type
for this case and update the method signature to reflect that it can throw. This
ensures callers are properly informed of the failure.
There was a problem hiding this comment.
추후 디버깅을 위해서라도 추가하는 것이 좋을 것 같습니다. 감사합니다~!
There was a problem hiding this comment.
@taipaise 동의해주셔서 감사합니다! 명시적인 에러 처리는 디버깅 시 문제를 빠르게 파악하는 데 정말 도움이 됩니다.
구현 시 다음과 같은 형태로 진행하시면 됩니다:
enum RoutineRepositoryError: Error {
case missingRoutineId
}
func updateRoutine(routineSummary: RoutineSummaryEntity, subRoutineSummaries: [SubRoutineSummaryEntity]) async throws {
guard let routineId = routineSummary.routineId else {
throw RoutineRepositoryError.missingRoutineId
}
// 기존 로직 계속...
}이렇게 하면 호출하는 쪽에서도 업데이트 실패를 명확히 인지할 수 있어 더 안정적인 코드가 될 것입니다.
/| /|
( :v: )
|(_)|
/ \
/ \
✏️ Learnings added
Learnt from: taipaise
PR: YAPP-Github/Bitnagil-iOS#33
File: Projects/DataSource/Sources/Repository/RoutineRepository.swift:45-46
Timestamp: 2025-08-04T23:43:28.481Z
Learning: taipaise는 디버깅을 위해 명시적인 에러 처리를 선호함. nil 체크 시 조용히 실패하는 것보다 에러를 던지는 방식을 추후 디버깅에 도움이 된다고 생각함.
Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.
🧠 Learnings used
Learnt from: choijungp
PR: YAPP-Github/Bitnagil-iOS#19
File: Projects/Domain/Sources/UseCase/Onboarding/OnboardingUseCase.swift:0-0
Timestamp: 2025-07-16T10:58:30.858Z
Learning: choijungp는 OnboardingUseCase의 convertToDictionary 함수에서 에러 처리 개선을 추후 고민하고 반영할 계획을 가지고 있음.
Learnt from: choijungp
PR: YAPP-Github/Bitnagil-iOS#19
File: Projects/Presentation/Sources/Common/PresentationDependencyAssembler.swift:0-0
Timestamp: 2025-07-16T10:57:16.559Z
Learning: choijungp는 추후 CustomAlertView를 만들어서 에러 처리를 UI로 해결하도록 수정할 계획을 가지고 있음.
Learnt from: choijungp
PR: YAPP-Github/Bitnagil-iOS#30
File: Projects/DataSource/Sources/NetworkService/Plugin/RefreshTokenPlugin.swift:42-43
Timestamp: 2025-07-30T03:56:18.617Z
Learning: choijungp는 현재 테스트 단계에서 RefreshTokenPlugin의 토큰 갱신 로직 디버깅을 위해 액세스 토큰과 리프레시 토큰의 실제 값을 로그에 기록하는 것을 선호함.
If you found this review helpful, would you consider giving us a shout-out on X?
Thank you for using CodeRabbit!
| public struct SubRoutineSummaryEntity: Decodable, Hashable { | ||
| public let subRoutineId: String? | ||
| public let subRoutineName: String? | ||
| public let sortOrder: Int? | ||
|
|
||
| public init( | ||
| subRoutineId: String?, | ||
| subRoutineName: String?, | ||
| sortOrder: Int? | ||
| ) { | ||
| self.subRoutineId = subRoutineId | ||
| self.subRoutineName = subRoutineName | ||
| self.sortOrder = sortOrder | ||
| } | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion
엔티티 설계에서 비즈니스 규칙을 고려한 개선이 필요합니다.
현재 모든 프로퍼티가 옵셔널로 정의되어 있어 PR 목표에서 언급된 API DTO와의 tight coupling 우려가 현실화되고 있습니다. 도메인 관점에서 다음 사항들을 검토해보세요:
subRoutineName은 필수값이어야 하지 않을까요?sortOrder는 기본값(예: 0)을 가져야 하지 않을까요?
도메인 중심의 설계로 개선을 제안합니다:
public struct SubRoutineSummaryEntity: Decodable, Hashable {
public let subRoutineId: String?
- public let subRoutineName: String?
+ public let subRoutineName: String
- public let sortOrder: Int?
+ public let sortOrder: Int
public init(
subRoutineId: String?,
- subRoutineName: String?,
+ subRoutineName: String,
- sortOrder: Int?
+ sortOrder: Int = 0
) {
self.subRoutineId = subRoutineId
self.subRoutineName = subRoutineName
self.sortOrder = sortOrder
}
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| public struct SubRoutineSummaryEntity: Decodable, Hashable { | |
| public let subRoutineId: String? | |
| public let subRoutineName: String? | |
| public let sortOrder: Int? | |
| public init( | |
| subRoutineId: String?, | |
| subRoutineName: String?, | |
| sortOrder: Int? | |
| ) { | |
| self.subRoutineId = subRoutineId | |
| self.subRoutineName = subRoutineName | |
| self.sortOrder = sortOrder | |
| } | |
| } | |
| public struct SubRoutineSummaryEntity: Decodable, Hashable { | |
| public let subRoutineId: String? | |
| public let subRoutineName: String | |
| public let sortOrder: Int | |
| public init( | |
| subRoutineId: String?, | |
| subRoutineName: String, | |
| sortOrder: Int = 0 | |
| ) { | |
| self.subRoutineId = subRoutineId | |
| self.subRoutineName = subRoutineName | |
| self.sortOrder = sortOrder | |
| } | |
| } |
🤖 Prompt for AI Agents
In Projects/Domain/Sources/Entity/SubRoutineSummaryEntity.swift lines 8 to 22,
the properties are all optional, causing tight coupling with the API DTO and
weakening domain integrity. Change subRoutineName to a non-optional property to
enforce it as a required field, and assign a default value (e.g., 0) to
sortOrder to avoid optionality. Adjust the initializer accordingly to reflect
these changes and ensure domain-driven design principles are followed.
There was a problem hiding this comment.
관련해서 회의 진행하고 리팩터링 예정입니다!
There was a problem hiding this comment.
@taipaise 좋은 접근 방식이네요! 팀과 함께 엔티티 설계에 대해 논의하고 체계적으로 리팩터링을 진행하시는 것이 현명한 판단입니다.
도메인 무결성과 API와의 결합도 문제를 함께 고려하시면서 진행하시길 바랍니다. 추후 리팩터링 결과가 궁금하네요! 🚀
🧠 Learnings used
Learnt from: choijungp
PR: YAPP-Github/Bitnagil-iOS#19
File: Projects/Domain/Sources/UseCase/Onboarding/OnboardingUseCase.swift:0-0
Timestamp: 2025-07-16T10:58:30.858Z
Learning: choijungp는 OnboardingUseCase의 convertToDictionary 함수에서 에러 처리 개선을 추후 고민하고 반영할 계획을 가지고 있음.
| let repeatType: RepeatType = weekDay.count == Week.allCases.count ? .daily : .week | ||
| let executionType: ExecutionType | ||
|
|
||
| if routine.executionTime == "00:00:00" { |
There was a problem hiding this comment.
🛠️ Refactor suggestion
매직 스트링 상수화 필요
"00:00:00"이 하드코딩되어 있습니다. 이는 서버와의 계약이므로 상수로 정의하는 것이 좋습니다.
+private enum Constants {
+ static let allDayTimeValue = "00:00:00"
+}
-if routine.executionTime == "00:00:00" {
+if routine.executionTime == Constants.allDayTimeValue {📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if routine.executionTime == "00:00:00" { | |
| // Add this at the top of RoutineCreationViewModel.swift (inside or just above the class) | |
| private enum Constants { | |
| static let allDayTimeValue = "00:00:00" | |
| } | |
| // …later in your method… | |
| // before | |
| - if routine.executionTime == "00:00:00" { | |
| // after | |
| + if routine.executionTime == Constants.allDayTimeValue { |
🤖 Prompt for AI Agents
In
Projects/Presentation/Sources/RoutineCreation/ViewModel/RoutineCreationViewModel.swift
at line 134, the string "00:00:00" is hardcoded as a magic string. Define this
value as a constant, preferably with a clear and descriptive name, to represent
the agreed server contract time format. Replace the hardcoded string with this
constant to improve maintainability and clarity.
There was a problem hiding this comment.
저도 그렇게 생각합니다. 다만 곧 시작 시간, 종료 시간에 대한 정책이 추가될 예정이라 우선은 하드 코딩으로 진행했습니다.
리뷰 감사합니다~
There was a problem hiding this comment.
@taipaise 네, 이해합니다! 시작 시간과 종료 시간 정책이 추가될 예정이라면 그때 함께 리팩토링하는 것이 더 효율적이겠네요. 전체적인 시간 관련 로직을 한 번에 정리하는 것이 좋은 접근 방법이라고 생각합니다.
향후 정책 추가 시에 시간 관련 상수들을 모두 정리해서 관리하시면 될 것 같습니다! 🐰
🐰💭
╭─────────────╮
│ 합리적인 판단! │
╰─────────────╯
🧠 Learnings used
Learnt from: choijungp
PR: YAPP-Github/Bitnagil-iOS#31
File: Projects/Presentation/Sources/Home/ViewModel/HomeViewModel.swift:97-103
Timestamp: 2025-08-01T06:38:18.687Z
Learning: choijungp의 HomeViewModel에서 fetchRoutines(for date: Date) 메서드는 기존 캐시 범위를 확장하는 것이 아니라, 요청된 날짜 주변의 새로운 데이터 청크를 가져오기 위해 oldestDate와 latestDate를 모두 업데이트한다. 과거 날짜 요청 시에는 해당 날짜의 1주 전~1일 전, 미래 날짜 요청 시에는 해당 날짜의 1일 후~1주 후 범위로 설정한다.
| } catch { | ||
|
|
||
| } |
There was a problem hiding this comment.
빈 catch 블록 문제
에러가 발생해도 사용자에게 알리지 않고 조용히 실패합니다. 적절한 에러 처리가 필요합니다.
최소한 로깅이라도 추가하거나, 사용자에게 피드백을 제공해야 합니다:
} catch {
-
+ // TODO: 에러 처리 구현
+ print("루틴 저장 실패: \(error)")
+ // 에러 상태를 PublishSubject로 전달하여 UI에서 처리
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| } catch { | |
| } | |
| } catch { | |
| // TODO: 에러 처리 구현 | |
| print("루틴 저장 실패: \(error)") | |
| // 에러 상태를 PublishSubject로 전달하여 UI에서 처리 | |
| } |
🤖 Prompt for AI Agents
In
Projects/Presentation/Sources/RoutineCreation/ViewModel/RoutineCreationViewModel.swift
around lines 292 to 294, the catch block is empty, causing errors to be silently
ignored. To fix this, add error handling by logging the error or providing user
feedback within the catch block to ensure errors are properly reported or
handled.
choijungp
left a comment
There was a problem hiding this comment.
루등, 루수가 너무너무 복잡하네요 ...... 진짜 고생하셨습니다 띵 !!!!!!!
하루에 몇 PR을 하신건지 !!!! 🔥🔥🔥🔥
일단 고민하셨던 부분에 대해 ...
1. 루틴 등록(createRoutine), 루틴 수정(updateRoutine)을 View에서는 루틴 저장(saveRoutine) 하나로 동작하게 하는 것이 의미 있는가?
흠 .. 어차피 분기처리를 하고 있으면 애초에 viewmodel 단에서 create - update를 분리하는 것두 ㄱㅊ아 보입니다 !!! (주관적인 판단임)
RoutineUseCase의 saveRoutine 함수에서 등록 및 수정에 필요한 값을 파라미터로 넘겨주는데
사실 등록할 때에는 수정에 필요한 deletedSubRoutineSummaries 이 녀석이 필요 없기 때문에 ... 함수를 2개 만들어두 된다고 생각하지만 ..........
그것은 추후 ....
2. Entity를 어떻게 정의 해야할까
이것슨 .. 제가 저번 PR에서 넘 대충 DTO - Entity를 서버에서 받은 Response와 동일하게 가져가자 .. 라고 해서 그 영향이 크지 않을까 싶습니다 ㅜㅜ
그리고 RoutineEntity를 제가 사용하고 있어서 1번 방법을 사용하지 않아주신것 .. . 매우 감동이 됩니다. . .......
아하 !!!! 좋습니다 !!!! 회의 때 Entity 정의를 함 하고 갑시두아 !!!!
논의해보고 싶은 부분들
1. View의 네이밍
우선 제가 첨에 View라고 정의한 이유는 정말정말 View의 역할만 했으면 하는 방향에서 .. 그르케 했습니다 ㅜㅜ
xxxView는 정말 멍청하게 View 역할만 하고 ViewController에 contentView에 xxxView를 넣어주자 라는 의미였지만
띵이 들어오기 전부터 View는 매우매우 똑똑했어요 .....
그래서 ViewController 네이밍 동의합니다 !!!
2. Repository의 역할
Entity에서 DTO로 매핑이 필요한 경우는 Request DTO일 때를 말씀하신거 맞으실까요 ??
띵의 말씀도 이해가 되지만 ...
Entity to DTO도 사실 DTO 객체에서 함수로 만들어서 매핑할 수 있지 않을까요 ?
struct DTO {
func toDTO(entity: Entity) -> DTO {
///
}
}하지만 이것은 정말 단순히 코드 가독성을 위해서 말씀드리는 말이긴 합니다. ..
(딩의 말씀대로 데이터 매핑을 repository가 가져가면 넘 복잡해질 수 있다고 판단되기도 해가주구요 ..)
하 .. 그른데 저렇게 하면 또 Entity랑 DTO랑 찐하게 엮여있긴 하네요 그럼 ...
DTO가 매핑의 역할까지 해야 하나 ??? 는 저도 좀 생각을 더 해보고 ..
회의에 참여하도록 해보겠습니다 !!!!
| public enum WeekType: String, CaseIterable { | ||
| case monday = "MONDAY" | ||
| case tuesday = "TUESDAY" | ||
| case wednesday = "WEDNESDAY" | ||
| case thursday = "THURSDAY" | ||
| case friday = "FRIDAY" | ||
| case saturday = "SATURDAY" | ||
| case sunday = "SUNDAY" | ||
| } |
There was a problem hiding this comment.
요 WeekType이 Public인 이유가 있을까용 ???
Review Note에서 말씀해주신 Entity <-> DTO를 Repository에서 해야 한다 ! 라는 것에서 일단 Public으로 열어두신 것인지 궁금함니다 !!!
또한 Presentation에 Week과 WeekType이 비슷한 역할을 한다고 생각하는데
그럼 차라리 Domain의 WeekType만 public으로 남겨두고 Presentation에서 필요한 값만 extension 해서 사용하는 것은 어떻게 생각하시나요 ?? (물론 배포 먼저)
There was a problem hiding this comment.
이 부분에 대해 리뷰 노트를 남기는 것을 깜빡했습니다!!! 역시 조이네요.!.!
말씀해주신대로 역할이 200% 동일한 녀석입니다.. 요 녀석을 추가한 이유는, 엔티티 내에서 사용하는 repeatDay를 문자열이 아닌 제한된 네임스페이스 안에서 다루는 것이 조금 더 적절하지 않을까하여 추가했습니다! 하지만 Presentation에서 사용하는 녀석과 역할이 겹쳐버려서,, 마음같아서는 Presentation의 Week을 도메인으로 옮기고 싶었지만!! 관련 내용에 대해 말씀드리고 진행하는 것이 좋을 것 같다 생각했습니다!
제안해주신 extension으로 활용하는 것은 좋아 입니다!! (생각지도 못한 방법 bbb)
| // | ||
| // Untitled.swift | ||
| // Domain | ||
| // | ||
| // Created by 이동현 on 8/3/25. | ||
| // | ||
|
|
There was a problem hiding this comment.
엠티 파일 발견 !!!!!!!!!!!!!!! 🚨🚨🚨🚨🚨🚨🚨🚨🚨
There was a problem hiding this comment.
악 이게 뭘까요.,.,.,.,.,.,.,.,.,. 수정하겠습니다
| let routineEntities = try await routineRepository.fetchRoutines(from: start, to: end) | ||
| return routineEntities |
There was a problem hiding this comment.
저도 몰랐는데!!!!Xcode 님이 알려주시길래 스윽 했습니다 ㅎㅎ
🌁 Background
👩💻 Contents
📝 Review Note
개발 지능이 많이 하락했구나~ 라는 것을 느낄 수 있었던 PR입니다. 그 이유는 다름 아닌 작업 순서 때문인데요, 지금도 왜 그랬는지 모르겠는데, DataSource 레이어쪽 작업을 먼저 진행했습니다. 때문에 이후 Domain 쪽 작업을 진행하며 Domain에서 약간의 구조 변경이 생김에 따라 DataSource를 다시 수정하게 되는 등 일을 두 번 하게 되었습니다. 반성하면서 다시 개발 지능을 쌓아가기로 다짐하며,, 본격적으로 약식 PR 설명회(라 쓰고 진짜 고봉밥 ㅠ)를 진행하겠습니다~
루틴 등록 / 수정하기
고민했던 부분들
1. 루틴 등록(createRoutine), 루틴 수정(updateRoutine)을 View에서는 루틴 저장(saveRoutine) 하나로 동작하게 하는 것이 의미 있는가?
body에 넘겨줘야 하는parameter의 형식도 다릅니다. 수정같은 경우는 각 루틴과 서브루틴의 ID값을 같이 넘겨주어야 하고, 서브루틴의 경우sortOrder를 또 넘겨줘야 합니다.Usecase를 사용할 때, 수정요청인지, 등록 요청인지 구분하지 않고 '루틴 저장' 이라는 메서드 하나만 바라보고 동작하게 했습니다. 왜 이렇게 했냐면!!!Presentation레이어에서 '등록', 그리고 '수정' 에 따른 분기처리를 하는 것 보다,Domain에서 등록/수정 여부를 판단하고 분기처리하는 것이Presentation쪽을 더 멍청하게 만들기 좋다 생각했기 때문입니다.Presentation측에서 분기처리를 통해 대단한 로직을 실행하는 것도 아니고, 분기처리도 단순히 routine에 id가 있냐 없냐로 처리할 수 있거든요2. Entity를 어떻게 정의 해야할까~
클린 아키텍쳐의 핵심은 잘 아시다시피, 의존성의 방향이 안쪽으로만 흐른다는 것입니다. 다시 말해 중앙에 있는 Domain이 중심을 잡고, Domain 외부의 layer가 Domain에 의존성이 있는 구조가 되는 것이죠. 처음에 구조를 나름 잘 잡아서, 전체 구조를 보면 의존성 역전을 통해 의존성이 안쪽 한 방향으로만 흐르게 구현이 되어있다 생각합니다.
한편, 루틴등록/수정을 구현하기 위해
RoutineSummaryEntity와SubRoutineSummaryEntity를 구현했는데요, 각 구조체들은 아래와 같이 생겼습니다.뭔가 이상하다는 생각이 드셨다면, 맞습니다 ㅠ 거의 이후 데이터 요청을 위해 변환될 DTO의 구조와 동일합니다. 아래는 DTO의 구조입니다.
이렇게
SummaryEntity를 구현하며 쉽게 API를 연결할 수는 잇엇지만,, 그리고 구조만 따져봤을때는Domain이DataSource를import하지 않으므로 의존성 방향을 잘 지키는 것처럼 보이지만,, 직접 구현한 저는 알고 있습니다 ㅠ 이 Entity는 직접적으로DataSource를 모르는 것일 뿐, 서버에서 내려주는 response와 요구하는 request에 엄청나게 의존하고 있다는 것을요..,.,., 다시 말해 DTO의 변경에 따라 이 Entity의 구조도 바뀔 가능성이 높다는 것이죠 (굉장히 잘못된 구조)원래 계획은, 루틴 등록, 수정 시에
UseCase에서는RoutineEntity를 들고 있고,Repository쪽에서RoutineEntity안에서 필요한 정보만 뽑아 쓸 수 있도록 하는 것을 생각했습니다. 하지만RoutineEntity에 생각보다 등록/수정 시에 사용하지 않는 정보가 많이 있었고, 아래 두 가지 방법을 고려했습니다.RoutineEntity에서 등록/수정에서 사용하지 않는 프로퍼티는 옵셔널로 변경하기1번 방법은 제가 구현하지 않는 부분에 대해서 많은 변경을 해야한다는 점에서, 말씀드리지 않고 진행하는 것은 문제가 있다 생각해서 진행하지 못했습니다. 또한 이 방법대로 진행하면,
RoutineEntity의 대부분의 프로퍼티가 옵셔널 상수가 된다는 점에서 적절한 방법이 아니라 생각했습니다. (엔티티의 거의 모든 프로퍼티가 옵셔널이라면, 차라리 엔티티의 프로퍼티를 쪼개는 것이 낫지 않나 하는 생각했습니다. 비유하자면 엔티티의 프로퍼티도 역할 분리를 하듯 더 작은 단위로 쪼개는 것이죠)2번 방법은 직관적으로도 지양하고 싶은 방법이라 느꼈습니다. 다른 사람이 유지보수를 위해 코드를 봤는데, 임의로 기본 값을 넣어주는 코드를 보면 왜 이 값을 넣어줘야 하는지 파악하기 힘들 것입니다. 또한 어떤 경우에는 기본 값을 넣어주고, 어떤 경우에는 넣지 않아야 하는지 파악하기 힘들 것이라 생각했습니다.
결론을 말씀드리자면, 엔티티를 한 번 같이 정리하고, 정의하면 좋을 것 같다는 생각이 들었습니다. 서버도 V2로 리팩토링이 예정된 만큼, 엔티티를 확실하게 정의하고 넘어가야 추후 외부의 변경에도 Domain의 변경을 최소화할 수 있을 것이라 생각하기 떄문입니다!
논의해보고 싶은 부분들
드디어.. Domain레이어를 처음 건드려 본 만큼, 구현하면서 논의해보면 좋겠다~ 하는 부분들이 있었습니다.
물론 아래서 드리는 말씀이 현재 방법이 틀렸다는 것은 절대 아니고, 가볍게 나눠보면 좋겠다~ 라고 들어주시면 감사하겠습니다 🙇♂️🙇♂️🙇♂️
1. View의 네이밍
2. Repository의 역할
Entity -> DTO의 매핑은 Entity가 DTO를 알 수 없기 때문에 DataSource layer에서 이뤄져야 합니다. 아마 이 과정은 Repository에서 일어나게 될 텐데요, Repository에서 Entity -> DTO의 매핑 책임을 가져간다면 반대의 경우도 repository가 가져가는 것이 조금 더 일관성 있을 것이라고 생각했습니다DTO <-> Entity 변환도 이 접점(Repository)에서 이뤄지는 것이 적절하다고 생각했습니다.위 두 가지 안건의 경우, 꼭 당장 정하거나 수정할 부분은 아니기 때문에 시간이 정말로 부족한 지금은 살짝 넘어가고 나중에 다시 이야기 해봐도 좋을 것 같습니다!
Summary by CodeRabbit
신규 기능
기능 개선
버그 수정
리팩터링/구조 개선