Conversation
There was a problem hiding this comment.
🤖 AI 코드 리뷰 - 아키텍처 관점
네이버 지도 SDK(NMapsMap)를 SPM으로 추가하고, 지도 기반 장소 선택 기능(PlaceSelectionViewController/ViewModel)을 구현한 PR이다. Domain 계층에 Repository 프로토콜과 UseCase를 정의하고, Data 계층에 Mock 구현체를 배치한 구조는 계층 분리 원칙에 부합한다. 다만 ViewController에서 UseCase와 Repository를 직접 생성·조합하는 패턴, ViewModel이 구체 UseCase 타입에 직접 의존하는 구조, CoreLocationRepository의 completion 콜백이 단일 호출 보장 없이 중복 실행될 수 있는 설계 문제가 확인된다.
There was a problem hiding this comment.
🤖 AI 코드 리뷰 - 아키텍처 관점
네이버 지도 SDK(NMapsMap) SPM 의존성 추가 및 지도 기반 장소 선택 기능을 구현한 PR이다. Domain/Data/Presentation 계층 분리는 전반적으로 유지되고 있으나, ViewController에서 UseCase와 Repository 구체 타입을 직접 생성하는 조합(composition) 방식이 계층 전반에 걸쳐 반복되고 있다. PlaceSelectionViewModel이 구체 UseCase 타입에 직접 의존하고 있어 확장성과 테스트 가능성에 구조적 제약이 있다. CoreLocationRepository의 completion 콜백은 단일 호출 후 nil로 초기화되지 않아 재사용 시 잠재적 문제가 있으나, 이는 아키텍처보다는 구현 수준 문제이므로 별도 언급하지 않는다. SceneDelegate에서 탭바 구성 로직이 직접 구현된 점은 규모가 커질수록 관리 지점이 분산될 수 있다.
sangYuLv
left a comment
There was a problem hiding this comment.
작업 내용과 리뷰 노트도 모두 확인했습니다!
수고 많으셨습니다 🦦🦦
(p.s. PR 생성할 때 AI 리뷰 라벨 달려있으면 두 번 트리거 되어서 중복으로 리뷰가 달려요. 라벨 없이 PR 생성한 뒤에 리뷰 라벨 달면 한 번만 받을 수 있습니다!)
| @unknown default: | ||
| break | ||
| } | ||
| } |
There was a problem hiding this comment.
아래 두 메소드와 시그니처 패턴을 통일해도 좋겠어요!
There was a problem hiding this comment.
locationManagerDidChangeAuthorization 메서드의 시그니처를 말씀하신게 맞을까요?
그렇다면 세 메서드 다 CLLocationManagerDelegate가 요구하는 고정된 프로토콜 메서드 이름이라 변경은 어려울거 같습니다🥲
|
|
||
| import UIKit | ||
| import Combine | ||
| import NMapsMap |
There was a problem hiding this comment.
외부 라이브러리 import를 view controller에 직접하지 않고, 하나의 파일(타입)에서 지도 뷰를 래핑하는 건 어떨까요?
There was a problem hiding this comment.
지도에 해당하는 UIView를 분리하겠습니다!
| /// 좌표 기준 근처 장소 조회를 위임하는 UseCase | ||
| private let getNearbyPlaceUseCase: GetNearbyPlaceUseCase | ||
| /// POI가 없을 때 좌표를 주소로 변환(fallback)하는 UseCase | ||
| private let reverseGeocodeUseCase: ReverseGeocodeUseCase |
There was a problem hiding this comment.
좌표 -> 근처 장소 조회는 "POI 우선, 없으면 역지오코딩 주소로 fallback" 구조라고 하셨는데,
근처 장소 조회 use case가 이 로직을 가지면 어떨까요?
근처 장소 조회와 좌표를 주소로 변환하는 로직이 각자 use case를 가지지 않고, 하나의 use case에서 처리되는 방향을 생각해봤습니다.
repository는 지금처럼 나눠져도 좋을 것 같아요.
There was a problem hiding this comment.
ReverseGeocodeUseCase가 독립적으로 사용되는 경우가 있을거같아서 분리했었어요
그런데, 현재 구상된 앱 기능에서는 없는거같아 하나의 use case에서 처리되게끔 수정했습니다 !!
| imageView.tintColor = .customRed | ||
| imageView.contentMode = .scaleAspectFit | ||
| return imageView | ||
| }() |


JIRA
📝 작업 내용
📌 요약
🔍 상세
1. 진입 흐름 (
AppointmentCreationViewController)onMapButtonTap)에서PlaceSelectionViewController를UINavigationController로 감싸 풀사이즈 시트로 present합니다.isModalInPresentation = true로 스와이프 닫기를 막고, 화면 안의 X 버튼으로만 닫히도록 했습니다.Place가 콜백으로 전달되어AppointmentCreationViewModel.setPlace(_:)로 이어집니다.2. 장소 선택 화면 (
PlaceSelectionViewController/PlaceSelectionViewModel)naverMapView.bottomAnchor == bottomCard.topAnchor),뷰 계층상 카드가 나중에 추가되어 카드의 그림자가 지도 위로 자연스럽게 번지도록 했습니다.
centerPinImageView)을 얹었고,카메라 이동이 멈추면(
NMFMapViewCameraDelegate.mapViewCameraIdle)핀의 실제 화면 위치를
projection.latlng(from:)으로 역산해 좌표를 계산합니다.PlaceSelectionViewModel은 중앙 좌표 변경 스트림에 디바운스(300ms)와최소 이동 거리 필터(20m 미만은 재조회 안 함)를 걸어 불필요한 조회를 줄였습니다.
(수치는 임의로 설정했습니다.)
근처 장소가 없을 때는 역지오코딩 결과(도로명 요약 + 상세주소)로 대체됩니다.
조회 자체가 실패하면 "장소를 불러오지 못했습니다"로 구분해서 표시합니다.
3. Naver Maps SDK 연동
NMapsMap패키지를 추가하고,AppDelegate에서NMFAuthManager.shared().ncpKeyId로 인증을 초기화합니다.Info.plist에$(NMF_CLIENT_ID)변수로 참조하고,실제 값은
.gitignore처리된Config.xcconfig(로컬 전용)에 둡니다.공개 저장소이므로 혹시 모를 과금을 방지하고자 값 자체를 커밋하지 않는 방식을 선택했습니다.
4. 실제 위치 연동
CoreLocationRepository를 새로 만들어MockLocationRepository대신 사용했습니다.권한 상태에 따라 요청/즉시 실패를 분기하고,
requestLocation()으로 1회성 좌표를 받아옵니다.5. 신규 UseCase / Repository / Core
GetNearbyPlaceUseCase+NearbyPlaceRepository(POI 조회, 반경 정책 포함)ReverseGeocodeUseCase+ReverseGeocodingRepository(주소 fallback)Coordinate.distance(to:)(Haversine 공식으로 두 좌표 간 거리 계산, km 단위)MockNearbyPlaceRepository,MockReverseGeocodingRepository)로 동작을 검증했습니다.💬 리뷰 노트
MapKit보다 국내 서비스(Naver/Kakao)가 우수하다고 생각했습니다.
지도와 길찾기 제공사를 맞춰두면 향후 좌표계 정합성 관리가 수월해지는 기타 이점도 있습니다.
좌표 기반으로 근처 POI(상호명)를 조회할 수 있는 API가 없는걸로 확인됩니다.
Reverse Geocoding은 도로명주소까지만 제공합니다.
TMap 장소 통합 검색 API 등이 있는 것으로 보이나,
정확한 파라미터/응답 품질/무료 이용량은 확인하지 못해 더 자세한 조사가 필요합니다.
searchOtherPlaceButton)은 액션이 연결되어 있지 않습니다Config.xcconfig파일 추가가 필요합니다WhereAreYou/WhereAreYou/Config.xcconfig경로에 위치해야 하는 파일로,Naver Maps SDK Client ID가 담겨 있습니다.
실제 API 연동 및 줌 레벨 연동은 이후 작업할 때 같이 고려되어야 할 것 같습니다.
별도 조사 후 문서로 작성하겠습니다. 이번 작업 범위에서는 제외하였습니다.
📸 영상 / 이미지
2026-07-28.02.50.30.mov
2026-07-28.02.52.42.mov